写诗

题面

达达是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\n", ans);
    }
    return 0;
}
posted @ 2020-06-02 21:22  洛绫璃  阅读(167)  评论(0编辑  收藏  举报