题面
达达是T国的公主,平时的一大爱好是作诗。
由于时间紧迫,达达作完诗之后还要虐OI,于是达达找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗。
因为达达喜欢对偶,所以达达规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。
而且达达认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。
于是达达请你安排选法。
问题简述:N个数,M组询问,每次询问需要你求出[l,r]中有多少个数出现正偶数次。
输入格式
输入第一行包含三个整数n、c以及m,表示文章字数、汉字的种类数、要选择m次。
第二行有n个整数,每个数A[i]在[1, c]间,代表一个编码为A[i]的汉字。
接下来m行每行两个整数l和r,设上一个询问的答案为ans(第一个询问时ans=0),令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交换L和R,则本次询问为[L,R]。
输出格式
输出共m行,每行一个整数,第i个数表示达达第i次能选出的汉字的最多种类数。
数据范围
1≤n,c,m≤105
输入样例:
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
输出样例:
2
0
0
0
1
题解
和普通的分块没啥区别, 块间直接预处理答案, 块内暴力, 只不过这道题卡的有点紧
要预处理, s[i][j] 表示在前 i 块, 字母j出现的次数
f[i][j] 为块 i 到 块 j 的答案
我一直tle, 主要在两个点
1.用的map(unordered_map), 尽管最多600+个数,但也相当拖时间, 改为手写的 queue
2.求f[i][j] 我用的三重循环 i,j,k(字母), 妥妥超时, 应该 (1~j * m) j 去算中间 特判什么时候算贡献(具体看代码)
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define fi first
#define se second
using namespace std;
typedef pair<int, int> PII;
typedef int ll;
const int N = 1e5 + 5, M = 317;
int n, c, k, t, ans;
int s[320][N], f[320][320];
int a[N], v[N], q[N], cnt[N];
int main()
{
scanf("%d%d%d", &n, &c, &k);
t = (n - 1) / M + 1;
rep (i, 1, t)
{
int nx = min(i * M, n);
rep (j, (i - 1) * M + 1, nx)
{
scanf("%d", a + j);
++s[i][a[j]];
}
rep (j, 1, c) s[i][j] += s[i - 1][j];
int cur = 0, cnt = 0;
per (j, nx, 1)
{
if (v[a[j]]) ++v[a[j]];
else v[a[j]] = 1, q[++cnt] = a[j];
if (v[a[j]] % 2 == 0) ++cur;
else if (v[a[j]] > 1) --cur;
if (j % M == 1) f[(j - 1) / M + 1][i] = cur;
}
rep (j, 1, cnt) v[q[j]] = 0;
}
while (k--)
{
int l, r; scanf("%d%d", &l, &r);
l = (l + ans) % n + 1, r = (r + ans) % n + 1;
if (l > r) swap(l, r);
ans = 0; int cnt = 0;
if (r - l + 1 >= (M << 1))
{
int L = (l - 1) / M + 1 + (l % M != 1);
int R = (r - 1) / M + 1 - (r % M != 0);
ans = f[L][R];
per (i, (L - 1) * M, l)
if (v[a[i]]) ++v[a[i]];
else
{
v[a[i]] = s[R][a[i]] - s[L - 1][a[i]] + 1;
q[++cnt] = a[i];
if (v[a[i]] > 1 && (v[a[i]] & 1)) --ans;
}
rep (i, R * M + 1, r)
if (v[a[i]]) ++v[a[i]];
else
{
v[a[i]] = s[R][a[i]] - s[L - 1][a[i]] + 1;
q[++cnt] = a[i];
if (v[a[i]] > 1 && (v[a[i]] & 1)) --ans;
}
}
else
rep (i, l, r)
if (v[a[i]]) ++v[a[i]];
else v[a[i]] = 1, q[++cnt] = a[i];
rep (i, 1, cnt) ans += (v[q[i]] % 2 == 0), v[q[i]] = 0;
printf("%d
", ans);
}
return 0;
}