BZOJ2821: 作诗(Poetize)

2821: 作诗(Poetize)

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

2
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 }
BZOJ2821

 

posted @ 2018-02-02 07:51  嘒彼小星  阅读(190)  评论(0编辑  收藏  举报