【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
Source
还没AC就写题解2333,原因是因为入BZ坑以来第二次遇到卡评测的事辣,虽然没法评测,遇到这种事莫名感兴趣XD。
比较神的分块辣,比之前做的麻烦多了,一开始感觉弹飞绵羊思路挺有趣,一看这道题,强制在线,10^5,smg,看题解,脑冻好大啊,我自己肯定想不出,首先我们需要预处理出两个东西。
1.f[i][j]:第i块到第j块中合法的个数。
2.前缀和[i][j]:前i个汉字中j出现的个数,当然并不是用2维数组的来实现的,而是在结构体中以汉字为第一关键字,以所在序号为第二关键字排序,用的时候二分即可。
这样,题目变得很明了了,查询时,对于同块或相邻块内的查询,直接暴力二分统计即可,若不在同一个块内,则开始直接ans=f[pos[l]+1][pos[r]-1](pos[]为所在块),也就是吧l,r之间的完整的块直接用f[][],剩下的暴力二分,注意细节。
但是!!!跟着黄学长写,分成sqrt(n)块的我t了,要分成sqrt(n/logn)块,不知道哪里写残了,一定要写个分成sqrt(n)的版本出来。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #define N 100010 7 #define sN 1555 8 #define inf 0x7fffffff 9 using namespace std; 10 struct data{int v,p;}b[N]; 11 int f[sN][sN],first[N],last[N],flag[N],temp[N],a[N],pos[N],L[sN],R[sN]; 12 int n,m,block,cnt,c; 13 bool cmp(data a,data b) {if (a.v<b.v) return 1; else if (a.v==b.v && a.p<b.p) return 1; return 0;} 14 inline int read() 15 { 16 char c; 17 int ans=0; 18 while ((c=getchar())==' ' || c=='\n' || c=='\r'); 19 ans=c-'0'; 20 while (isdigit(c=getchar())) ans=ans*10+c-'0'; 21 return ans; 22 } 23 void part1_pre() 24 { 25 for (int i=1;i<=cnt;i++) 26 { 27 int tot; 28 for (int j=L[i];j<=n;j++) temp[a[j]]=0; 29 tot=0; 30 for (int j=L[i];j<=n;j++) 31 { 32 if (!(temp[a[j]]&1) && temp[a[j]]) tot--; 33 temp[a[j]]++; 34 if (!(temp[a[j]]&1)) tot++; 35 f[i][pos[j]]=tot; 36 } 37 } 38 for (int i=1;i<=n;i++) 39 { 40 b[i].v=a[i]; 41 b[i].p=i; 42 } 43 sort(b+1,b+n+1,cmp); 44 for (int i=1;i<=n;i++) 45 { 46 if (!first[b[i].v]) first[b[i].v]=i; 47 last[b[i].v]=i; 48 } 49 } 50 int findup(int x,int v) 51 { 52 int tem=0,l=first[v],r=last[v]; 53 while (l<=r) 54 { 55 int mid=(l+r)>>1; 56 if (x<b[mid].p) r=mid-1; 57 else {l=mid+1;tem=mid;} 58 } 59 return tem; 60 } 61 int finddown(int x,int v) 62 { 63 int tem=inf,l=first[v],r=last[v]; 64 while (l<=r) 65 { 66 int mid=(l+r)>>1; 67 if (x>b[mid].p) l=mid+1; 68 else {r=mid-1;tem=mid;} 69 } 70 return tem; 71 } 72 int find(int x,int y,int v) {return max(findup(y,v)-finddown(x,v)+1,0);} 73 int query(int x,int y) 74 { 75 int ans=0,t,t1; 76 if (pos[x]==pos[y] || pos[x]+1==pos[y]) 77 { 78 for (int i=x;i<=y;i++) 79 { 80 if (!flag[a[i]]) 81 { 82 t=find(x,y,a[i]); 83 if (!(t&1)) {ans++;flag[a[i]]=1;} 84 } 85 } 86 for (int i=x;i<=y;i++) flag[a[i]]=0; 87 } 88 else 89 { 90 int l=L[pos[x]+1],r=R[pos[y]-1]; 91 ans=f[pos[x]+1][pos[y]-1]; 92 for (int i=x;i<l;i++) 93 { 94 if (!flag[a[i]]) 95 { 96 flag[a[i]]=1; 97 t=find(x,y,a[i]);t1=find(l,r,a[i]); 98 if (!(t&1)) 99 {if ((t1&1) || !t1) ans++;} 100 else 101 if (!(t1&1) && t1) ans--; 102 } 103 } 104 for (int i=r+1;i<=y;i++) 105 { 106 if (!flag[a[i]]) 107 { 108 flag[a[i]]=1; 109 t=find(x,y,a[i]);t1=find(l,r,a[i]); 110 if (!(t&1)) 111 {if ((t1&1) || !t1) ans++;} 112 else 113 if (!(t1&1) && t1) ans--; 114 } 115 } 116 for (int i=x;i<l;i++) flag[a[i]]=0; 117 for (int i=r+1;i<=y;i++) flag[a[i]]=0; 118 } 119 return ans; 120 } 121 int main() 122 { 123 int ans=0; 124 n=read();c=read();m=read(); 125 block=sqrt((double)n/log((double)n)*log(2)); 126 for (int i=1;i<=n;i++) a[i]=read(); 127 if (n%block) cnt=n/block+1; 128 else cnt=n/block; 129 for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1; 130 for(int i=1;i<=cnt;i++) 131 L[i]=(i-1)*block+1,R[i]=i*block; 132 R[cnt]=n; 133 part1_pre(); 134 for (int i=1;i<=m;i++) 135 { 136 137 int l=read(),r=read(); 138 int x=(l+ans)%n+1,y=(r+ans)%n+1; 139 if (x>y) swap(x,y); 140 ans=query(x,y); 141 printf("%d\n",ans); 142 } 143 return 0; 144 }
—Anime Otaku Save The World.