【BZOJ2821】作诗(Poetize) 分块
【BZOJ2821】作诗(Poetize)
Description
神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗。由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选法。LYD这种傻×当然不会了,于是向你请教……问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶数次。
Input
输入第一行三个整数n、c以及m。表示文章字数、汉字的种类数、要选择M次。第二行有n个整数,每个数Ai在[1, c]间,代表一个编码为Ai的汉字。接下来m行每行两个整数l和r,设上一个询问的答案为ans(第一个询问时ans=0),令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交换L和R,则本次询问为[L,R]。
Output
输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。
Sample Input
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
Sample Output
2
0
0
0
1
0
0
0
1
HINT
对于100%的数据,1<=n,c,m<=10^5
题解:分块大法太强了~
我们先分块,对于每一个询问[l,r]我们都可以将它拆成中间一堆大块和两边的小块,设f[i][j]表示从第i个块到第j个块的答案,我们先枚举每个块,暴力扫所有i块后面的点,这样就能边扫边预处理出f[i][j],到时候我们就直接调用就好了,现在我们处理两边的小块
我们将两边小块里的元素暴力扫一遍,然后排个序,这样我们就能得到每个汉字出现的次数了,这时我们就需要提前预处理出一个g[i][j],表示在1~i的块里j出现的个数,然后我们就能得出每个汉字的总个数了
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; int n,m,c,siz,ans,num; int f[320][320],g[320][100010],v[100010],s[100010],p[640]; int main() { scanf("%d%d%d",&n,&c,&m); int i,j,a,b; siz=int(sqrt(1.0*n)); for(i=0;i<n;i++) scanf("%d",&v[i]),g[i/siz][v[i]]++; for(i=0;i<=n/siz;i++) { if(i) for(j=1;j<=c;j++) g[i][j]+=g[i-1][j]; memset(s,0,sizeof(s)); for(j=i*siz;j<n;j++) { s[v[j]]++; if(s[v[j]]==2) f[i][j/siz]++; if(s[v[j]]==3) f[i][j/siz]--,s[v[j]]=1; if(j&&j%siz==0) f[i][j/siz]+=f[i][j/siz-1]; } } for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); a=(a+ans)%n,b=(b+ans)%n; num=0; if(a>b) swap(a,b); if(a/siz==b/siz) { ans=0; for(j=a;j<=b;j++) p[num++]=v[j]; sort(p,p+num); int pre=0; for(j=0;j<num;j++) { if(j&&p[j]!=p[j-1]) { ans+=(pre%2==0)?1:0; pre=0; } pre++; } ans+=(pre%2==0)?1:0; } else { ans=f[a/siz+1][b/siz-1]; for(j=a;j<(a/siz+1)*siz;j++) p[num++]=v[j]; for(j=b/siz*siz;j<=b;j++) p[num++]=v[j]; sort(p,p+num); int pre=0; for(j=0;j<num;j++) { if(j&&p[j]!=p[j-1]) { if(g[b/siz-1][p[j-1]]>g[a/siz][p[j-1]]&&((g[b/siz-1][p[j-1]]-g[a/siz][p[j-1]])%2==0)) ans--; if((pre+g[b/siz-1][p[j-1]]-g[a/siz][p[j-1]])%2==0) ans++; pre=0; } pre++; } if(g[b/siz-1][p[num-1]]>g[a/siz][p[num-1]]&&((g[b/siz-1][p[num-1]]-g[a/siz][p[num-1]])%2==0)) ans--; if((pre+g[b/siz-1][p[num-1]]-g[a/siz][p[num-1]])%2==0) ans++; } printf("%d\n",ans); } return 0; }
| 欢迎来原网站坐坐! >原文链接<