BZOJ2821: 作诗(Poetize)
2821: 作诗(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 1123 Solved: 354
[Submit][Status]
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
题解:
如果不强制在线的话可以用莫队来搞,强制在线的话就分块了。
相邻块里暴力,否则中间的大块的答案已知,考虑两小块对答案的影响,
可以用二分来求出小块内的元素在整个区间内出现的次数以及在中间大块中出现的次数,根据奇偶性来更新答案
因为大块的话,复杂度为O(块大小*logn),小块的复杂度为O(块大小)
如果每块为√n,可能会T,所以考虑把每块小一点,但又不能太小,选sqrt(n/logn)比较合适
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<queue> 11 #include<string> 12 #define inf 1000000000 13 #define maxn 100000+1000 14 #define maxm 2000 15 #define eps 1e-10 16 #define pa pair<int,int> 17 #define for0(i,n) for(int i=0;i<=n;i++) 18 #define for1(i,n) for(int i=1;i<=n;i++) 19 #define for2(i,x,y) for(int i=x;i<=y;i++) 20 using namespace std; 21 inline int read() 22 { 23 int x=0,f=1;char ch=getchar(); 24 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 25 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 26 return x*f; 27 } 28 struct rec{int x,id;}b[maxn]; 29 int n,m,c,ans,block,a[maxn],l[maxn],r[maxn],pos[maxn],f[maxm][maxm],sum[maxn]; 30 bool mark[maxn]; 31 inline bool cmp(rec a,rec b) 32 { 33 return a.x<b.x||(a.x==b.x&&a.id<b.id); 34 } 35 inline int findup(int val,int pos) 36 { 37 int ll=l[val],rr=r[val],mid; 38 while(ll<=rr) 39 { 40 mid=(ll+rr)>>1; 41 if(b[mid].id>pos)rr=mid-1;else ll=mid+1; 42 } 43 return rr; 44 } 45 inline int finddown(int val,int pos) 46 { 47 int ll=l[val],rr=r[val],mid; 48 while(ll<=rr) 49 { 50 mid=(ll+rr)>>1; 51 if(b[mid].id>=pos)rr=mid-1;else ll=mid+1; 52 } 53 return ll; 54 } 55 inline int find(int val,int x,int y) 56 { 57 return findup(val,y)-finddown(val,x)+1; 58 } 59 void ask(int x,int y) 60 { 61 x=(x+ans)%n+1;y=(y+ans)%n+1;if(x>y)swap(x,y); 62 ans=0; 63 int bx=pos[x],by=pos[y],r=bx*block,l=(by-1)*block+1,t1,t2; 64 if(by-bx<=1) 65 { 66 for2(i,x,y) 67 { 68 sum[a[i]]++; 69 if(sum[a[i]]&1&&sum[a[i]]!=1)ans--; 70 if(!(sum[a[i]]&1))ans++; 71 } 72 for2(i,x,y)sum[a[i]]=0; 73 } 74 else 75 { 76 ans=f[bx+1][by-1]; 77 for2(i,x,r)if(!mark[a[i]]) 78 { 79 mark[a[i]]=1; 80 t1=find(a[i],x,y);t2=find(a[i],r+1,l-1); 81 if(t1&1&&!(t2&1)&&t2)ans--; 82 if(!(t1&1)&&(t2&1||!t2))ans++; 83 } 84 for2(i,l,y)if(!mark[a[i]]) 85 { 86 mark[a[i]]=1; 87 t1=find(a[i],x,y);t2=find(a[i],r+1,l-1); 88 if(t1&1&&!(t2&1)&&t2)ans--; 89 if(!(t1&1)&&(t2&1||!t2))ans++; 90 } 91 for2(i,x,r)mark[a[i]]=0; 92 for2(i,l,y)mark[a[i]]=0; 93 } 94 printf("%d\n",ans); 95 } 96 int main() 97 { 98 freopen("input.txt","r",stdin); 99 freopen("output.txt","w",stdout); 100 n=read();c=read();m=read(); 101 block=sqrt((double)n/log((double)n)*log(2)); 102 for1(i,n) 103 { 104 a[i]=read();b[i].x=a[i];b[i].id=i; 105 pos[i]=(i-1)/block+1; 106 } 107 sort(b+1,b+n+1,cmp); 108 for1(i,n+1) 109 if(b[i].x!=b[i-1].x) 110 { 111 r[b[i-1].x]=i-1;l[b[i].x]=i; 112 } 113 for1(i,pos[n]) 114 { 115 ans=0;memset(sum,0,sizeof(sum)); 116 for2(j,(i-1)*block+1,n) 117 { 118 sum[a[j]]++; 119 if(sum[a[j]]&1&&sum[a[j]]!=1)ans--; 120 if(!(sum[a[j]]&1))ans++; 121 f[i][pos[j]]=ans; 122 } 123 } 124 memset(sum,0,sizeof(sum)); 125 ans=0; 126 while(m--)ask(read(),read()); 127 return 0; 128 }