BZOJ2821: 作诗(Poetize)
2821: 作诗(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 3300 Solved: 965
[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
【题解】
不知是什么原因,我用上次做蒲公英的写法写这道题,T了。。。
改用陈立杰论文的写法,又T了。。。
“写这个题以后,我也没干别的,大概三个写法,第一个,就是vector存位置二分它,第二个,就是分块排序二分,第三个,就是预处理每个块中每个数出现次数。如果说还有一点优化,就是加了输出优化,这个对时间秒杀hzw题解意义很重大的,还有取摸优化也是很重要的。很惭愧,就做了一点微小的工作,谢谢大家。” ——姜则岷
发现蒲公英也可以用这个写法,更快。。
设块大小为m预处理p[i][j]表示第i块到第j块有多少出现偶数次的,复杂度n^2/m
预处理pp[i][j]表示第i块,j出现了多少次,然后做前缀和,复杂度m * n(数的个数与n相同)
查询时,中间块直接获得,两边的数依次枚举,查询pp,根据奇偶分情况讨论,复杂度nm(询问次数与n相同)
总复杂度m * n + nm + n^2/m,设m = n^x
2 * n^(x + 1) + n^(2 - x) <= 4√n^3 当且仅当x + 1 = 2 - x,即x = 0.5时取等号
m = √n
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <string> 10 #include <cmath> 11 #include <sstream> 12 #define min(a, b) ((a) < (b) ? (a) : (b)) 13 #define max(a, b) ((a) > (b) ? (a) : (b)) 14 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 15 template<class T> 16 inline void swap(T &a, T &b) 17 { 18 T tmp = a;a = b;b = tmp; 19 } 20 inline void read(int &x) 21 { 22 x = 0;char ch = getchar(), c = ch; 23 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 24 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 25 if(c == '-') x = -x; 26 } 27 const int INF = 0x3f3f3f3f; 28 const int MAXN = 100000 + 10; 29 const int SMAXN = 320; 30 int size,group,l[SMAXN],r[SMAXN],num[MAXN],n,c[MAXN],m,typ,p[SMAXN][SMAXN],sum[SMAXN][MAXN]; 31 inline int find(int ll, int rr, int x) 32 { 33 return sum[rr][x] - sum[ll - 1][x]; 34 } 35 void make_p() 36 { 37 register int i,j,k,ans,now; 38 for(i = 1;i <= group;++ i) 39 { 40 ans = 0, now = i; 41 for(int j = l[i];j <= r[i];++ j) ++ sum[i][num[j]]; 42 for(int j = l[i];j <= n;++ j) 43 { 44 ++ c[num[j]]; 45 if(c[num[j]] != 1) 46 { 47 if(c[num[j]] & 1) -- ans; 48 else ++ ans; 49 } 50 if(r[now] == j) p[i][now] = ans, ++ now; 51 } 52 for(int j = l[i];j <= n;++ j) c[num[j]] = 0; 53 } 54 for(i = 2;i <= group;++ i) 55 for(int j = 1;j <= typ;++ j) 56 sum[i][j] += sum[i - 1][j]; 57 } 58 int query(int ll, int rr) 59 { 60 int bl = (ll - 1) / size + 1, br = (rr - 1) / size + 1, ans = 0; 61 if(bl + 2 <= br) 62 { 63 ans = p[bl + 1][br - 1]; 64 for(int i = ll;i <= r[bl];++ i) ++ c[num[i]]; 65 for(int i = l[br];i <= rr;++ i) ++ c[num[i]]; 66 for(int i = ll;i <= r[bl];++ i) 67 if(c[num[i]]) 68 { 69 int tmp = 0; 70 tmp = find(bl + 1, br - 1, num[i]); 71 if((tmp & 1) && (c[num[i]] & 1)) ++ ans; 72 else if(!tmp && !(c[num[i]] & 1)) ++ ans; 73 else if(tmp && !(tmp & 1) && (c[num[i]] & 1)) -- ans; 74 c[num[i]] = 0; 75 } 76 for(int i = l[br];i <= rr;++ i) 77 if(c[num[i]]) 78 { 79 int tmp = 0; 80 tmp = find(bl + 1, br - 1, num[i]); 81 if((tmp & 1) && (c[num[i]] & 1)) ++ ans; 82 else if(!tmp && !(c[num[i]] & 1)) ++ ans; 83 else if(tmp && !(tmp & 1) && (c[num[i]] & 1)) -- ans; 84 c[num[i]] = 0; 85 } 86 } 87 else 88 { 89 for(int j = ll;j <= rr;++ j) 90 { 91 ++ c[num[j]]; 92 if(c[num[j]] == 1) continue; 93 if(c[num[j]] & 1) -- ans; 94 else ++ ans; 95 } 96 for(int j = ll;j <= rr;++ j) c[num[j]] = 0; 97 } 98 return ans; 99 } 100 std::ostringstream os; 101 int main() 102 { 103 read(n), read(typ), read(m); 104 for(register int i = 1;i <= n;++ i) read(num[i]); 105 int M = 1;for(;(1 << M) <= n;++ M);-- M; 106 size = sqrt(n); 107 for(register int i = 1;i <= n;i += size) 108 l[++ group] = i, r[group] = min(i + size - 1, n); 109 make_p(); 110 register int pre = 0, l, r; 111 for(register int i = 1;i <= m;++ i) 112 { 113 read(l), read(r); 114 l = (l + pre), r = (r + pre); 115 if(l >= n) l -= n; 116 if(r >= n) r -= n; 117 l += 1, r += 1; 118 if(l > r) swap(l, r); 119 pre = query(l, r);/*printf("%d", pre);putchar('\n');*/ 120 os << pre << '\n'; 121 } 122 std::cout << os.str(); 123 return 0; 124 }