bzoj 2821
2821: 作诗(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 3526 Solved: 1047
[Submit][Status][Discuss]
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
Source
思路: 数列分块算法
类似bzoj 2724
cnt[i][j]表示前j块里面j出现了几次
num[i][j]表示第i块到第j个块有多少个数出现了偶数次
考虑不完整的两块,即最左边和最右边的两块,先统计这两块里面每个数出现了几次,然后用这些数去原有答案(即中间块)
如果两边某个数出现了奇数次,中间这个数是奇数次,那么ans++
如果两边某个数出现了奇数次,中间这个数是偶数次,那么ans--
如果两边某个数出现了偶数次,中间这个数没有出现过,那么ans++
注意: 这里由于如果按照sqrt(n) 来确定块的大小的化,要超空间,可以让B等于400,这样内存可以卡过去。
时间复杂度O(nsqrt(n))
#include<bits/stdc++.h> using namespace std; #define F(i,a,b) for(int i=a;i<=b;i++) #define D(i,a,b) for(int i=a;i>=b;i--) #define ms(i,a) memset(a,i,sizeof(a)) #define st(x) ( (x-1)*B+1) #define ed(x) min(x*B,n) #define bl(x) ( (x-1)/B+1) int inline read(){ int x=0; char c=getchar(); while (c<'0' || c>'9') c=getchar(); while (c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x; } int const maxn=100003; int cnt[maxn][251],B=400,num[251][251],n,m,a[maxn],t,c[maxn],mx,tmp[maxn]; int query(int l,int r){ int x=bl(l); int y=bl(r); int ans=0; if(x+1<=y-1) ans=num[x+1][y-1]; tmp[0]=0; if(x==y){ F(i,l,r) { c[a[i]]++; if (c[a[i]]==1) tmp[++tmp[0]]=a[i]; if(c[a[i]]>1) { if(c[a[i]]&1) ans--; else ans++; } } }else { int s=l; int e=ed(x); F(i,s,e) { if(!c[a[i]]) tmp[++tmp[0]]=a[i]; c[a[i]]++; } s=st(y); e=r; F(i,s,e) { if(!c[a[i]]) tmp[++tmp[0]]=a[i]; c[a[i]]++; } F(i,1,tmp[0]){ int x1=c[tmp[i]] & 1; int x2=cnt[tmp[i]][y-1]-cnt[tmp[i]][x]; if(x1 && x2 && (x2&1)) ans++; if(x1 && x2 && !(x2&1)) ans--; if(!x1 && !x2 ) ans++; } } F(i,1,tmp[0]) c[tmp[i]]=0; return ans; } int main(){ n=read(); t=read(); m=read(); F(i,1,n) a[i]=read(),mx=max(mx,a[i]); t=bl(n); F(i,1,t){ ms(0,c); int s=st(i); int e=ed(i); F(j,s,e) c[a[j]]++; F(j,1,mx) cnt[j][i]=cnt[j][i-1]+c[j]; } F(i,1,t){ ms(0,c); int ans=0; F(j,i,t){ int s=st(j); int e=ed(j); F(p,s,e) { c[a[p]]++; if(c[a[p]]>1 && c[a[p]]% 2==1) ans--; else if(c[a[p]] % 2==0 && c[a[p]]>1) ans++; } num[i][j]=ans; } } int x=0; ms(0,c); while (m--){ int l=read(); int r=read(); l=(l+x) % n; r=(r+x) % n; if(l>r) swap(l,r); printf("%d\n",x=query(l+1,r+1) ) ; } return 0; }