• BZOJ 2821: 作诗(Poetize) | 分块


    题目:

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


    分块.

    预处理:

    ans[i][j]表示i块到j块的答案;

    cnt[i][j]表示i数前j块出现的次数

    询问:

    ret=l到r包含的整块部分答案,然后暴力处理块外的数出现次数.

    我们发现关于每个数x以下情况可以影响到答案

    1.x出现奇数次,整块中出现了正偶数次,ret--

    2.x出现奇数次,整块中出现了奇数次,ret++

    3.x出现偶数次,整块中出现了奇数次,ret++

    而x在整块出现次数可以用cnt轻松的求出

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define N 100005
    #define sq 320
    using namespace std;
    int cnt[N][sq],sum[N],n,c,m,S,s,bl[N],br[N],a[N],ans[sq][sq],lastans, vis[N];
    void Init()
    {
        for (int i=0;i<n;i++)
        if (i%S==0) br[s]=i-1,bl[++s]=i;
        br[s]=n-1,bl[s+1]=br[s+1]=n;
        for (int i=1;i<=s;i++)
        {
        for (int j=1;j<=c;j++)
            cnt[j][i]=cnt[j][i-1];
        for (int h=bl[i],t=br[i];h<=t;h++)
            cnt[a[h]][i]=++sum[a[h]];
        }
        memset(sum,0,sizeof(sum));
        for (int i=1;i<=s;i++)
        {
        int k=bl[i],tmp=0,t,c;
        for (int j=k;j<n;j++) sum[a[j]]=0;
        for (int j=i;j<=s;j++)
        {
            t=br[j];
            for (;k<=t;k++)
            {
            if (vis[a[k]]==i)
            {
                c=++sum[a[k]];
                if (c%2==0) tmp++;
                else tmp--;
            }
            else vis[a[k]]=i,sum[a[k]]=1;
            }
            ans[i][j]=tmp; 
        }
        }
        memset(vis,0,sizeof(vis));
    }
    int Query(int l,int r)
    {
        if (r-l<2*S)
        {
        int tmp=0;
        for (int i=l;i<=r;i++)
            if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
            else ++sum[a[i]];
        for (int i=l;i<=r;i++)
            if (vis[a[i]])
            tmp+=!(sum[a[i]]%2),vis[a[i]]=0;
        return tmp;
        }
        int L=l/S+1,R=r/S+1;
        if (l==bl[L]) L--;
        if (r==br[R]) R++;
        int st=bl[R],ed=br[L],res=ans[L+1][R-1];
        for (int i=l;i<=ed;i++)
        if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
        else sum[a[i]]++;
        for (int i=st;i<=r;i++)
        if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
        else sum[a[i]]++;
        for (int i=l;i<=ed;i++)
        if (vis[a[i]])
        {
            int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L];
            if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--;
            if (cnt2==0 && cnt1%2==0) res++;
            if (cnt2%2==1 && cnt1%2==1) res++;
            sum[a[i]]=vis[a[i]]=0;
        }
        for (int i=st;i<=r;i++)
        if (vis[a[i]])
        {
            int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L];
            if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--;
            if (cnt2==0 && cnt1%2==0) res++;
            if (cnt2%2==1 && cnt1%2==1) res++;
            sum[a[i]]=vis[a[i]]=0;
        }
        return res;
    }
    int main()
    {
        scanf("%d%d%d",&n,&c,&m);S=sqrt(n);
        for (int i=0;i<n;i++)
        scanf("%d",a+i);
        Init();
         for (int i=1,l,r;i<=m;i++)
        {
        scanf("%d%d",&l,&r);
        l=(l+lastans)%n+1;
        r=(r+lastans)%n+1;
        if (l>r) swap(l,r);
        printf("%d
    ",lastans=Query(l-1,r-1));
        }
        return 0;
    }
  • 相关阅读:
    AngularJs+bootstrap搭载前台框架——准备工作
    AngularJs+bootstrap搭载前台框架——基础页面
    AngularJs调用Restful实现CRUD
    用AngularJs制作单页面应用
    Unity3D中使用Projector生成阴影
    Linux OpenGL 实践篇-16 文本绘制
    leetcode 233. 数字1的个数
    leetcode 189. 轮转数组
    leetcode 127 单词接龙
    leetcode 4.两个排序数组的中位数
  • 原文地址:https://www.cnblogs.com/mrsheep/p/8178346.html
Copyright © 2020-2023  润新知