洛谷P4135 作诗(分块)

典型的分块例题,和区间众数差不多,本题必须用不带log的做法,因此我们考虑前缀和,因为显然的是,区间中某数的个数都可以用前缀和表示

我们设计一个前缀和表示前i块数j的个数是多少个

然后设计一个d数组表示i-j块之间的答案是多少,这就是分块的基本思想,大块直接维护答案,小块暴力枚举

之后在暴力枚举的时候,通过奇偶来判断答案

我的写法常数有点大,估计是多了一个没有必要的离散化。吸吸氧气就能过了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int d[320][320];
int s[320][100010];
int cnt[N];
int n,c,m;
int a[N];
vector<int> b;
int block;
void init(){
    block=sqrt(n);
    int l,r;
    for(l=1;l<=n;l++){
        if((l-1)%block==0){
            for(r=1;r<=(int)b.size();r++){
                s[(l-1)/block+1][r]=s[(l-1)/block][r];
            }
        }
        s[(l-1)/block+1][a[l]]++;
    }
    for(l=1;l<=n;l+=block){
        memset(cnt,0,sizeof cnt);
        int res=0;
        for(r=l;r<=n;r++){
            cnt[a[r]]++;
            if(cnt[a[r]]%2==0)
                res++;
            if(cnt[a[r]]%2&&cnt[a[r]]>1)
                res--;
            if(r%block==0||r==n)
                d[(l-1)/block+1][(r-1)/block+1]=res;
        }
    }
    for(int i=1;i<=n;i++)
        cnt[a[i]]=0;
    /*for(int i=1;i<=(n-1)/block+1;i++){
        for(int j=i;j<=(n-1)/block+1;j++)
            cout<<d[i][j]<<" ";
        cout<<endl;
    }*/
}
int cal(int l,int r,int x){
    return s[r][x]-s[l][x];
}
int query(int l,int r){
    int idx1=(l-1)/block+1;
    int idx2=(r-1)/block+1;
    int ans=0;
    int i,j;
    if(idx1+1<idx2)
        ans=d[idx1+1][idx2-1];
    if(idx1==idx2){
        for(i=l;i<=r;i++){
            if(cnt[a[i]]){
                if(cnt[a[i]]&1)
                    ans++;
                else
                    ans--;
            }
            cnt[a[i]]++;
        }
        for(i=l;i<=r;i++)
            cnt[a[i]]=0;
    }
    else{
        for(i=l;i<=idx1*block;i++){
            if(!cnt[a[i]])
                cnt[a[i]]=cal(idx1,idx2-1,a[i]);
            if(cnt[a[i]]){
                if(cnt[a[i]]&1)
                    ans++;
                else
                    ans--;
            }
            cnt[a[i]]++;
        }
        for(i=(idx2-1)*block+1;i<=r;i++){
            if(!cnt[a[i]])
                cnt[a[i]]=cal(idx1,idx2-1,a[i]);
            if(cnt[a[i]]){
                if(cnt[a[i]]&1)
                    ans++;
                else
                    ans--;
            }
            cnt[a[i]]++;
        }
        for(i=l;i<=idx1*block;i++)
            cnt[a[i]]=0;
        for(i=(idx2-1)*block+1;i<=r;i++)
            cnt[a[i]]=0;

    }

    return ans;
}
int main(){
    cin>>n>>c>>m;
    int i;
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b.push_back(a[i]);
    }
    sort(b.begin(),b.end());
    b.erase(unique(b.begin(),b.end()),b.end());
    for(i=1;i<=n;i++){
        a[i]=lower_bound(b.begin(),b.end(),a[i])-b.begin()+1;
    }
    init();
    int last=0;
    int l,r;
    while(m--){
        scanf("%d%d",&l,&r);
        l=(l+last)%n+1;
        r=(r+last)%n+1;
        if(l>r)
            swap(l,r);
        last=query(l,r);
        printf("%d
",last);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12768091.html