序列
题意
有长度为\(n\)的\(a,b\)两个序列,有m种操作,操作有两种类型,\(1\ x\ y\)代表这个操作可以让\(a[x]\)和\(a[y]\)同时加\(1\)或者减\(1\),\(2\ x\ y\)则代表一个加\(1\)另一个减\(1\)。
每种操作可以无限次进行,问能否让\(a\)与\(b\)完全相等。
题解
先让 \(a[i]=a[i]-b[i]\) ,现在的目的就是让 \(a[i]=0\)
首先分两种部分分情况:
1.只有两个点 2.操作只有2
只有两个点的情况很容易处理,讨论一下就可以了。
操作只有2的情况也很容易处理,把操作看成边,发现2边连接的连通块之和为0的话,这个连通块就可以通过不断的2操作和b完全一样。
整体做法就是结合上面两种情况,我们先把2边连通块缩成一个点,这时候整个图就剩1边了,发现性质,a-b-c这样一个结构,可以看做是a和c连了个2边。
让新的图建立起新的2边,然后再缩点,这个过程可以通过黑白染色实现。这样缩下去,每个连通块的点数不超过\(2\),依次判断就行。
复杂度是\(O(n)\)。
代码
考场没写出来,只写了暴力。
冒泡排序
题意
\(n\)长度序列\(p\),\(m\)个操作,操作分两种,\(1\ x\)表示当前序列\(x\)位和\(x+1\)位交换,\(2\ k\)表示询问如果当前序列冒泡\(k\)轮后的序列的逆序对和。
题解
我们逆序对计算方式是算前面比当前数大的个数。那么会发现,一个序列冒泡一次,每个位置的逆序对数量都会\(-1\),除非那个位置逆序对数为0。
那么我们用树状数组(线段树也行)去存储逆序对数,树状数组第k个位置存的就是逆序对数为k的位置的逆序对数。查询时查询大于\(k\)的和,然后每个大于\(k\)的位置都减去\(k\)
即。
代码
#include <bits/stdc++.h> using namespace std; const int MAXN=200005; int n,m; int p[MAXN]; long long sum[MAXN],maxn[MAXN],tot[MAXN]; int k[MAXN]; void update(int l,long long v,long long *sum){ while(l){ sum[l]+=v; l-=(l&(-l)); } } long long get(int l,long long *sum){ long long an=0; while(l<=n){ an+=sum[l]; l+=(l&(-l)); } return an; } int main() { freopen("bubble.in","r",stdin); freopen("bubble.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&p[i]); update(p[i],1,maxn); k[i]=get(p[i]+1,maxn); update(k[i],k[i],sum); update(k[i],1,tot); } for(int i=1;i<=m;i++){ int t,x; scanf("%d%d",&t,&x); if(t==1){ if(p[x]>p[x+1]) { update(k[x+1],-k[x+1],sum); update(k[x+1],-1,tot); k[x+1]--; update(k[x+1],k[x+1],sum); update(k[x+1],1,tot); } else{ update(k[x],-k[x],sum); update(k[x],-1,tot); k[x]++; update(k[x],k[x],sum); update(k[x],1,tot); } swap(p[x],p[x+1]); swap(k[x],k[x+1]); } else{ long long ans=get(x+1,sum)-x*get(x+1,tot); printf("%lld\n",ans); } } return 0; }
最小环
题意
给你个\(n\)的环,环上每个位置都有值,给\(m\)次询问,对于每次询问给个\(k\),你需要把环上的值交换顺序,以让环上每个相距为\(k\)的数相乘的和最大。
题解
对于询问\(k\),相当于是把环分成\(gcd(n,k)\)个小环,发现每个小环都是从大到小分配数的规律,然后因为环的种类只有\(\sum gcd(i,n)\)种,预处理即可。复杂度\(o(n\sqrt{n})\)
代码
#include <bits/stdc++.h> using namespace std; int n,m; long long a[400005]; bool vis[400005]; long long ans[400005]; int main() { freopen("ring.in","r",stdin); freopen("ring.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),ans[0]+=a[i]*a[i]; sort(a+1,a+1+n); for(int i=1;i*2<=n;i++){ int g=__gcd(i,n); if(vis[g])continue; vis[g]=1; int l=n/g; int p=n-l+1; ans[g]+=a[n]*a[n-1]; for(int j=n;j>=1;j--){ if(j==p){ if(j>1)ans[g]+=a[j-1]*a[j-2]; p=j-l;continue; } ans[g]=ans[g]+(a[j]*a[max(j-2,p)]); } } for(int i=1;i<=m;i++){ int k;scanf("%d",&k); if(k==0)printf("%lld\n",ans[0]); else{ k=__gcd(k,n); printf("%lld\n",ans[k]); } } return 0; }
来源:https://www.cnblogs.com/redegg/p/12433639.html