【bzoj 2821】 作诗 题意&题解&代码(C++)

来源:互联网 发布:格式化数据恢复 编辑:程序博客网 时间:2024/06/13 06:23

题目链接:

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

权限题,附题意:
这里写图片描述
这里写图片描述
这里写图片描述

题解:

分块题,他要求在线处理区间问题,很明显是为了卡莫队这种神奇算法,首先将序列分块,按 sqrt(n) (即根号n)分块,然后预处理出一个数组 f[i][j] 表示从第 i 块到第 j 块内,满足题意的答案,还要处理出另一个数组 cnt[i][j] 表示前 i 块中数字 j 出现了多少次,(不要担心数组太大开不下,三千两百万它还真就是存下了,o.o!),这样的话当询问区间 (i,j)时,我们利用 f[i][j] 通过各种判断首先将包含在这个区间里的块的答案统计出来,再利用 cnt[i][j] 将两头或是一头没有达到一整快的部分暴力的统计,一边统计一边修改已经得到的答案即可,时限还是够的。

注意题中一个特别坑的地方,
这里写图片描述
他特别心机的的在mod与n+1 之间加了一个空格,让大家以为是mod(n+1)实际上却是(mod n)+1。。2333


代码

#include<iostream>#include<algorithm>#include<stdio.h>#include<string.h>#include<math.h>#define maxn (100005)#define maxs (320)using namespace std;int vis[maxn],ans,L,R,len,n,num,c,m,sq[maxn],f[maxs][maxs],cnt[maxs][maxn],a[maxn],st[maxs],tmp[maxn];void solve(int l,int r)//计算 l,r{    if (sq[l]==sq[r] || sq[l]+1==sq[r])    {        for (int i=l;i<=r;i++)        {            vis[a[i]]++;            if (vis[a[i]]%2==0) ans++;            else if (vis[a[i]]!=1) ans--;        }        for (int i=l;i<=r;i++)        vis[a[i]]=0;        return ;    }    if (l==st[sq[l]] && r==st[sq[r]+1]-1)    {        ans=f[sq[l]][sq[r]];        return ;        }    else if (l==st[sq[l]])    {        ans=f[sq[l]][sq[r]-1];        for (int i=st[sq[r]];i<=r;i++)        vis[a[i]]=cnt[sq[r]-1][a[i]]-cnt[sq[l]-1][a[i]];        for (int i=st[sq[r]];i<=r;i++)        {            vis[a[i]]++;            if (vis[a[i]]%2==0) ans++;            else if (vis[a[i]]!=1) ans--;               }                for (int i=st[sq[r]];i<=r;i++)                vis[a[i]]=0;        return ;                    }    else if (r==st[sq[r]+1]-1)    {        ans=f[sq[l]+1][sq[r]];        for (int i=l;i<st[sq[l]+1];i++)        vis[a[i]]=cnt[sq[r]][a[i]]-cnt[sq[l]][a[i]];        for (int i=l;i<st[sq[l]+1];i++)        {            vis[a[i]]++;            if (vis[a[i]]%2==0) ans++;            else if (vis[a[i]]!=1) ans--;           }                for (int i=l;i<st[sq[l]+1];i++)                vis[a[i]]=0;        return ;    }    else    {        int x=sq[l]+1;        int y=sq[r]-1;        ans=f[x][y];        for (int i=l;i<st[x];i++)        vis[a[i]]=cnt[y][a[i]]-cnt[x-1][a[i]];        for (int i=st[y+1];i<=r;i++)        vis[a[i]]=cnt[y][a[i]]-cnt[x-1][a[i]];        for (int i=l;i<st[x];i++)        {            vis[a[i]]++;            if (vis[a[i]]%2==0) ans++;            else if (vis[a[i]]!=1) ans--;           }        for (int i=st[y+1];i<=r;i++)        {            vis[a[i]]++;            if (vis[a[i]]%2==0) ans++;            else if (vis[a[i]]!=1) ans--;               }           for (int i=l;i<st[x];i++) vis[a[i]]=0;        for (int i=st[y+1];i<=r;i++) vis[a[i]]=0;           return ;    }}int main(){    scanf("%d%d%d",&n,&c,&m);    len=sqrt(n);    for (int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        sq[i]=(i-1)/len+1;        cnt[sq[i]][a[i]]++;        if (sq[i]!=sq[i-1])        st[sq[i]]=i;    }    num=sq[n];    for (int i=1;i<=num;i++)    for (int j=1;j<=c;j++)    cnt[i][j]+=cnt[i-1][j];    //预处理 cnt数组    for (int i=1;i<=num;i++)    {        int tans=0;        for (int j=1;j<=c;j++)        tmp[j]=0;        for (int j=st[i];j<=n;j++)        {            tmp[a[j]]++;            if (tmp[a[j]]%2==0) tans++;            else if (tmp[a[j]]!=1) tans--;            f[i][sq[j]]=tans;        }    }//预处理 f 数组    ans=0;    for (int i=1;i<=m;i++)    {        scanf("%d%d",&L,&R);        L=(L+ans)%n+1;        R=(R+ans)%n+1;        ans=0;        if (L>R) swap(L,R);        solve(L,R);        printf("%d\n",ans);    }}

不得不说,csdn的博客编辑最近好像十分的恶心。。。

0 0
原创粉丝点击