BZOJ 2821作诗(Poetize) 分块

Description

有一个长度为n的序列,序列每个元素的范围[1,c],有m个询问x y,表示区间[x,y]中出现正偶数次的数的种类数。

Solution

大力分块解决问题。

把序列分块,f[i][j]表示第i块到第j块的答案,并记录块的前缀数的出现次数。

f[i][j]直接暴力算,块的前缀数的出现次数也可以直接算,都是nsqrt(n)。

遇到询问x y,中间答案的块可以直接统计,然后再暴力统计左右两边零碎的贡献,也是nsqrt(n)。

Code

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <string>
 5 #include <algorithm>
 6 #include <cmath>
 7
 8 using namespace std;
 9
10 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
11 const int maxn = 1e5+10;
12 int n, c, m, a[maxn];
13 int bel[maxn], l[maxn], r[maxn];
14 int cnt[350][maxn], s_block, t[maxn], f[350][350];
15
16 int solve(int x, int y)
17 {
18     int L = bel[x], R = bel[y];
19     if (L == R)
20     {
21         REP(i, x, y) t[a[i]] = 0;
22         int ret = 0;
23         REP(i, x, y) if (t[a[i]] ++) ret += (t[a[i]]&1) ? -1 : 1;
24         return ret;
25     }
26     else
27     {
28         int ret = f[L+1][R-1];
29         REP(i, x, r[L]) t[a[i]] = 0;
30         REP(i, l[R], y) t[a[i]] = 0;
31         REP(i, x, r[L]) if (!t[a[i]]) t[a[i]] = cnt[R-1][a[i]]-cnt[L][a[i]];
32         REP(i, l[R], y) if (!t[a[i]]) t[a[i]] = cnt[R-1][a[i]]-cnt[L][a[i]];
33         REP(i, x, r[L]) if (t[a[i]] ++) ret += (t[a[i]]&1) ? -1 : 1;
34         REP(i, l[R], y) if (t[a[i]] ++) ret += (t[a[i]]&1) ? -1 : 1;
35         return ret;
36     }
37 }
38
39 int main()
40 {
41     scanf("%d %d %d", &n, &c, &m);
42     REP(i, 1, n) scanf("%d", &a[i]);
43     int block = int(sqrt(n));
44     REP(i, 1, n)
45     {
46         bel[i] = i/block+1, r[bel[i]] = i;
47         if (i == 1 || bel[i] != bel[i-1]) l[bel[i]] = i;
48     }
49     s_block = n/block+1;
50     REP(i, 1, s_block)
51     {
52         REP(j, 1, c) t[j] = 0;
53         REP(j, i, s_block)
54         {
55             f[i][j] = (j == i) ? 0 : f[i][j-1];
56             REP(k, l[j], r[j]) if (t[a[k]] ++) f[i][j] += (t[a[k]]&1) ? -1 : 1;
57         }
58     }
59     REP(i, 1, s_block)
60     {
61         REP(j, 1, c) cnt[i][j] = cnt[i-1][j];
62         REP(j, l[i], r[i]) cnt[i][a[j]] ++;
63     }
64     int x, y, ans = 0;
65     while (m --)
66     {
67         scanf("%d %d", &x, &y);
68         x = (x+ans)%n+1, y = (y+ans)%n+1;
69         if (x > y) swap(x, y);
70         printf("%d\n", ans = solve(x, y));
71     }
72     return 0;
73 }

时间: 2024-12-20 04:16:01

BZOJ 2821作诗(Poetize) 分块的相关文章

BZOJ 2821: 作诗(Poetize)( 分块 )

分块,分成N^0.5块.O(N^1.5)预处理出sm[i][j]表示前i块中j的出现次数, ans[i][j]表示第i~j块的答案. 然后就可以O(N^0.5)回答询问了.总复杂度O((N+Q)N^0.5) ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<

[BZOJ 2821] 作诗(Poetize) 【分块】

题目链接:BZOJ - 2821 题目分析 因为强制在线了,所以无法用莫队..可以使用分块来做. 做法是,将 n 个数分成 n/x 个块,每个块大小为 x .先预处理出 f[i][j] ,表示从第 i 个块到第 j 个块的出现次数为偶数的数的个数. 这个复杂度是 n * (n / x) 的. 然后把数与位置存在结构体里,按照数字第一关键字,位置为第二关键字排序.这样是为了方便之后二分查找 [l, r] 中 Num 出现了几次. 对于每次询问,先把答案加上中间包含的整块的答案.然后对于两边至多 2

【BZOJ2821】作诗(Poetize) 分块

Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗.因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次.而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!).于是SHY请LYD安排选法.LYD这种傻×当然不会了

BZOJ 2821 作诗

类似上题的做法,f[i][j]表示第i块到第j块出现偶数次的数有多少个,然后调整一下. 复杂度n√nlogn. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define maxn 100050 using namespace std; int n,c,m,a[maxn],cnt[maxn],blo[maxn]

巴蜀4384 -- 【模拟试题】作诗(Poetize)

Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗.因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次.而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!).于是SHY请LYD安排选法.LYD这种傻×当然不会了

BZOJ2821作诗【分块】

Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗.因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次.而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!).于是SHY请LYD安排选法.LYD这种傻×当然不会了

【分块】bzoj2821 作诗(Poetize)

分块,预处理出: ①第i块到第j块之间的偶数值的种类数. ②在前i块中,每个值出现的次数.(前缀和)(差分) 每次询问时,对于不在整块中的元素,进行暴力转移. 注意:减少memset的使用,千万不要写100000个memset,否则会TLE,宁愿每次询问之后O(sqrt(n))地一个个减掉那个记录每个值出现次数的临时数组. Code: 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #incl

bzoj2821 作诗(Poetize)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2821 [题解] 今天看了黄学长的分块专项 感觉十分科学就来刚刚分块了. 这题我们套用区间众数的办法.令f[i,j]表示i块到j块的答案,g[i,j]表示1...i块,数字为j的有多少个. 然后我们大区间个数可以直接调用,两边暴力做. 注意清零问题不能出现复杂度退化. 有两种办法,一个是把所有即将出现的数的位置都清空或赋值,一种是排序后,找到第一个的时候赋值,后面累加. 后面那个是popoq

「luogu4135」作诗

「luogu4135」作诗 传送门 分块好题. 预处理出 \(f[i][j]\) 表示 \(i\) 号块到 \(j\) 号块的答案,\(num[i][k]\) 表示 \(k\) 在前 \(i\) 块的出现次数,暴力预处理,暴力查询,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) fr