首页 > 代码库 > bzoj2821 作诗(Poetize)

bzoj2821 作诗(Poetize)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2821

【题解】

今天看了黄学长的分块专项 感觉十分科学就来刚刚分块了。

这题我们套用区间众数的办法。令f[i,j]表示i块到j块的答案,g[i,j]表示1...i块,数字为j的有多少个。

然后我们大区间个数可以直接调用,两边暴力做。

注意清零问题不能出现复杂度退化。

有两种办法,一个是把所有即将出现的数的位置都清空或赋值,一种是排序后,找到第一个的时候赋值,后面累加。

后面那个是popoqqq大爷写的(似乎强行多了个log)

事实证明这个log很慢的。。

技术分享

大概……也就两倍把

两份代码:

O(n根号n)

技术分享
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e5 + 10, N = 320, BLOCK = 350;

# define RG register
# define ST static

int n, C, q, B;
int a[M], bl[M];
int bst[N], bnd[N];
int t[M];
int f[N][N];
int g[N][M];
// 1..i block j appear ? time

inline void prepare(int x) {
    int cur = 0, tem = x;
    memset(t, 0, sizeof t);
    for (int i=bst[x]; i<=n; ++i) {
        ++t[a[i]];
        if(t[a[i]]&1) {
            if(t[a[i]] == 1);
            else --cur;
        } else ++cur;
        if(bnd[tem] == i) {
            f[x][tem] = cur;
            ++tem;
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &C, &q);
    for (int i=1; i<=n; ++i) {
        scanf("%d", a+i);
        bl[i] = (i-1)/BLOCK+1;
    }
    B = bl[n];
    for (int i=1; i<=B; ++i) bst[i] = (i-1)*BLOCK+1, bnd[i] = min(n, i*BLOCK);
    for (int i=1; i<=B; ++i) prepare(i);
    for (int i=1; i<=B; ++i) {
        for (int j=1; j<=C; ++j) g[i][j] = g[i-1][j];
        for (int j=bst[i]; j<=bnd[i]; ++j) g[i][a[j]] ++;
    }
    int l, r, lst=0;
    while(q--) {
        scanf("%d%d", &l, &r);
        l = (l+lst)%n+1, r = (r+lst)%n+1;
        if(l>r) swap(l, r);
//        printf("%d %d\n", l, r);
        if(bl[l] == bl[r]) {
            int cur = 0;
            for (int i=l; i<=r; ++i) t[a[i]] = 0;
            for (int i=l; i<=r; ++i) {
                ++t[a[i]];
                if(t[a[i]]&1) {
                    if(t[a[i]] == 1);
                    else --cur;
                } else ++cur;
            }
            printf("%d\n", lst = cur);
            continue;
        } 
        int cur = 0;
        if(bl[r]-bl[l] != 1) cur = f[bl[l]+1][bl[r]-1];
        for (int i=l; i<=bnd[bl[l]]; ++i) t[a[i]] = g[bl[r]-1][a[i]] - g[bl[l]][a[i]];
        for (int i=bst[bl[r]]; i<=r; ++i) t[a[i]] = g[bl[r]-1][a[i]] - g[bl[l]][a[i]];
        for (int i=l; i<=bnd[bl[l]]; ++i) {
            int x = a[i];
            ++t[x];
            if(t[x]&1) {
                if(t[x] == 1);
                else --cur;
            } else ++cur;
        }
        for (int i=bst[bl[r]]; i<=r; ++i) {
            int x = a[i];
            ++t[x];
            if(t[x]&1) {
                if(t[x] == 1);
                else --cur;
            } else ++cur;
        } 
        printf("%d\n", lst = cur);
    }
    
    return 0;
}
View Code

O(n根号nlogn)

技术分享
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e5 + 10, N = 320, BLOCK = 350;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, C, q, B;
int a[M], bl[M];
int bst[N], bnd[N];
int t[M], tt[M], tn=0;
int f[N][N];
int g[N][M];
// 1..i block j appear ? time

inline void prepare(int x) {
    int cur = 0, tem = x;
    for (int i=bst[x]; i<=n; ++i) {
        ++t[a[i]];
        if(t[a[i]]&1) {
            if(t[a[i]] == 1);
            else --cur;
        } else ++cur;
        if(bnd[tem] == i) {
            f[x][tem] = cur;
            ++tem;
        }
    }
    memset(t, 0, sizeof t);
}

int main() {
    scanf("%d%d%d", &n, &C, &q);
    for (int i=1; i<=n; ++i) {
        scanf("%d", a+i);
        bl[i] = (i-1)/BLOCK+1;
    }
    B = bl[n];
    for (int i=1; i<=B; ++i) bst[i] = (i-1)*BLOCK+1, bnd[i] = min(n, i*BLOCK);
    for (int i=1; i<=B; ++i) prepare(i);
    for (int i=1; i<=n; ++i) g[bl[i]][a[i]]++;
    for (int i=1; i<=B; ++i)
        for (int j=1; j<=C; ++j)
            g[i][j] += g[i-1][j];
    int l, r, lst=0;
    while(q--) {
        scanf("%d%d", &l, &r);
        l = (l+lst)%n+1, r = (r+lst)%n+1;
        if(l>r) swap(l, r);
//        printf("%d %d\n", l, r);
        if(bl[l] == bl[r]) {
            int cur = 0;
            for (int i=l; i<=r; ++i) {
                ++t[a[i]];
                if(t[a[i]]&1) {
                    if(t[a[i]] == 1);
                    else --cur;
                } else ++cur;
            }
            printf("%d\n", lst = cur);
            for (int i=l; i<=r; ++i) --t[a[i]];
            continue;
        } 
        tn = 0;
        int cur = 0;
        if(bl[r]-bl[l] != 1) cur = f[bl[l]+1][bl[r]-1];
        for (int i=l; i<=bnd[bl[l]]; ++i) tt[++tn] = a[i];
        for (int i=bst[bl[r]]; i<=r; ++i) tt[++tn] = a[i];
        sort(tt+1, tt+tn+1);
//        for (int i=1; i<=tn; ++i) printf("%d ", tt[i]);
//        puts("\n=====");
        for (int i=1; i<=tn; ++i) {
            int x = tt[i];
            if(tt[i] != tt[i-1]) t[x] = g[bl[r]-1][x]-g[bl[l]][x];
            ++t[x];
            if(t[x]&1) {
                if(t[x] == 1);
                else --cur;
            } else ++cur;
        }
        printf("%d\n", lst = cur);
        for (int i=1; i<=tn; ++i) t[tt[i]] = 0;
    }
    
    return 0;
}
View Code

 

bzoj2821 作诗(Poetize)