P4135 作诗——分块

题目:https://www.luogu.org/problemnew/show/P4135

分块大法;

块之间记录答案,每一块记录次数前缀和;

注意每次把桶中需要用到位置赋值就好了;

为什么加了特判会 T 一个点?

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int const maxn=1e5+5;
int n,c,m,mod,a[maxn],ans,blk[maxn],base,t[maxn],cnt[320][maxn],bst[320],bed[320],f[320][320];
void pre(int x)
{
    int tmp=0,tem=x;
    memset(t,0,sizeof t);
    for(int i=bst[x];i<=n;i++)
    {
        t[a[i]]++;
        if(t[a[i]]%2==0)tmp++;
        else if(t[a[i]]>1)tmp--;
        if(i==bed[tem])f[x][tem]=tmp,tem++;
    }
}
int main()
{
    scanf("%d%d%d",&n,&c,&m); 
    base=sqrt(n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),blk[i]=(i-1)/base+1;
    for(int i=1;i<=blk[n];i++)bst[i]=(i-1)*base+1,bed[i]=min(n,i*base);
    for(int i=1;i<=blk[n];i++)pre(i);
    for(int i=1;i<=blk[n];i++)
    {
        for(int k=1;k<=c;k++)cnt[i][k]=cnt[i-1][k];
        for(int j=bst[i];j<=bed[i];j++)cnt[i][a[j]]++;
    }    
    for(int i=1,l,r;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        l=(l+ans)%n+1; r=(r+ans)%n+1;
        if(l>r)swap(l,r);
//        if(l==r){printf("0\n"); ans=0; continue;}//ans=0!!!  //加特判变慢了??? 
        ans=0;
        if(blk[l]==blk[r])
        {
            for(int j=l;j<=r;j++)t[a[j]]=0;
            for(int j=l;j<=r;j++)
            {
                t[a[j]]++;
                if(t[a[j]]%2==0)ans++;
                else if(t[a[j]]>1)ans--;
            }
            printf("%d\n",ans);
        }
        else
        {
            if(blk[r]>blk[l]+1)ans=f[blk[l]+1][blk[r]-1];
            for(int j=l;j<=bed[blk[l]];j++)t[a[j]]=cnt[blk[r]-1][a[j]]-cnt[blk[l]][a[j]];
            for(int j=bst[blk[r]];j<=r;j++)t[a[j]]=cnt[blk[r]-1][a[j]]-cnt[blk[l]][a[j]];
            for(int j=l;j<=bed[blk[l]];j++)
            {
                t[a[j]]++;
                if(t[a[j]]%2==0)ans++;
                else if(t[a[j]]>1)ans--;
            }
            for(int j=bst[blk[r]];j<=r;j++)
            {
                t[a[j]]++;
                if(t[a[j]]%2==0)ans++;
                else if(t[a[j]]>1)ans--;
            }
            printf("%d\n",ans);
        }    
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9302300.html