Luogu 4135 作诗

lyd大神犇的狗粮题……   

终于填掉了这个大坑, 之前由于有一些事情一直没有想清楚, 一直没有动手写此题,就记录一下那些“有一些事情”
1、对于对答案的贡献问题
若要统计[l, r]中所有颜色的贡献:
在扫描的过程中记录出现的次数cnt, 若cnt第一次变到2的时候, 把当前答案加一, 如果当前cnt大于二, 答案应当减一

**简单分析:**当一个数第一次到达出现2次的时候,应当显然地对答案产生了贡献, 当这个数在第三次出现的时候, 它之前产生的贡献就被消除了, 第四次出现的时候就又会被累加回来, 所以这样是对的

2、复杂度分析, 对于这样的块大小在块内不套log的情况下应当是取sqrt(n) 最优 (然而可能我太蒟了, 跑得很卡)

3、一开始犯了一个脑残的错误

pos[x] + 1 <= pos[y]

分分钟跑成暴力……

Code:

#include <cstdio>
#include <cmath>
using namespace std;

const int N = 1e5 + 5;
const int B = 320;

int n, m, c, bnum, a[N], l[B], r[B], pos[N];
int sum[B][N], ans[B][B], cnt[N];

inline void read(int &X) {
    X = 0;
    char ch = 0;
    int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void prework() {
    bnum = sqrt(n);
    for(int i = 1; i <= bnum; i++) {
        l[i] = (i - 1) * bnum + 1;
        r[i] = i * bnum;
    }
    if(r[bnum] < n) {
        bnum++;
        l[bnum] = r[bnum - 1] + 1;
        r[bnum] = n;
    }

    for(int i = 1; i <= bnum; i++)
        for(int j = l[i]; j <= r[i]; j++) {
            pos[j] = i;
            sum[i][a[j]]++;
        }
    for(int i = 1; i <= c; i++)
        for(int j = 1; j <= bnum; j++)
            sum[j][i] += sum[j - 1][i];

    for(int i = 1; i <= bnum; i++) {
        int res = 0;
        for(int j = l[i]; j <= n; j++) {
            cnt[a[j]]++;
            if(cnt[a[j]] > 0 && cnt[a[j]] % 2 == 0) res++;
            else if(cnt[a[j]] > 2) res--;
            ans[i][pos[j]] = res;
        }
        for(int j = l[i]; j <= n; j++)
            cnt[a[j]]--;
    }
}

inline void swap(int &x, int &y) {
    int t = x; 
    x = y;
    y = t;
}

int query(int x, int y) {
    int res = 0;
    if(pos[x] + 1 >= pos[y]) {
        for(int i = x; i <= y; i++) {
            cnt[a[i]]++;
            if(cnt[a[i]] > 0 && cnt[a[i]] % 2 == 0) res++;
            else if(cnt[a[i]] > 2) res--;
        }
        for(int i = x; i <= y; i++)
            cnt[a[i]]--;
    } else {
/*        for(int i = x; i <= r[pos[x]]; i++)
            cnt[a[i]]++;
        for(int i = l[pos[y]]; i <= y; i++)
            cnt[a[i]]++; */

        res = ans[pos[x] + 1][pos[y] - 1];
        for(int i = x; i <= r[pos[x]]; i++) {
            cnt[a[i]]++;
            int tmp = sum[pos[y] - 1][a[i]] - sum[pos[x]][a[i]] + cnt[a[i]]; 
/*            if(tmp > 0) {
                if(tmp % 2 == 0) {
                    if(cnt[a[i]] % 2 != 0) res--;
                } else {
                    if(cnt[a[i]] % 2 != 0) res++;
                    else res--;
                }
            } else {
                if(cnt[a[i]] > 0 && cnt[a[i]] % 2 == 0)
                    res++;
            } */
            
            if(tmp > 0 && tmp % 2 == 0) res++;
            else if(tmp > 2) res--;
        }
        for(int i = l[pos[y]]; i <= y; i++) {
            cnt[a[i]]++;
            int tmp = cnt[a[i]] + sum[pos[y] - 1][a[i]] - sum[pos[x]][a[i]]; 
/*            if(tmp > 0) {
                if(tmp % 2 == 0) {
                    if(cnt[a[i]] % 2 != 0) res--;
                } else {
                    if(cnt[a[i]] % 2 != 0) res++;
                    else res--;
                }
            } else {
                if(cnt[a[i]] > 0 && cnt[a[i]] % 2 == 0)
                    res++;
            } */

            if(tmp > 0 && tmp % 2 == 0) res++;
            else if(tmp > 2) res--;

        }

        for(int i = x; i <= r[pos[x]]; i++)
            cnt[a[i]]--;
        for(int i = l[pos[y]]; i <= y; i++)
            cnt[a[i]]--;
    }
    return res;
}

int main() {
    read(n), read(c), read(m);
    for(int i = 1; i <= n; i++)
        read(a[i]);
    prework();
    
    for(int lastAns = 0, x, y; m--; ) {
        read(x), read(y);
        x = (x + lastAns) % n + 1, y = (y + lastAns) % n + 1;
        if(x > y) swap(x, y);
        printf("%d\n", lastAns = query(x, y));
    }

    return 0;
}
原文地址:https://www.cnblogs.com/CzxingcHen/p/9466328.html