bzoj2821: 作诗(Poetize)
分块
分sqrt(n)块
F[i][j]表示块i到块j的答案
s[i][j]表示数字i在前j块内出现了几次
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #define N 100005 #define M 233 #define L(x) (n*((x)-1)/m+1) #define R(x) (n*(x)/m) using namespace std; inline int read(){ int ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } int n,a[N],l; int bl[N],m; int F[M][M]; int s[N][M]; int cnt[N]; void precompute(){ m=min((int)sqrt(n),230); memset(cnt,0,sizeof(cnt)); for (int i=1;i<=m;++i){ for (int j=L(i);j<=R(i);++j){ bl[j]=i;++cnt[a[j]]; } for (int j=1;j<=l;++j) s[j][i]=cnt[j]; } memset(F,0,sizeof(F)); for (int i=1;i<=m;++i){ memset(cnt,0,sizeof(cnt)); int now=0; for (int j=i;j<=m;++j){ for (int k=L(j);k<=R(j);++k){ if ((++cnt[a[k]])<2) continue; now-=(cnt[a[k]]&1)*2-1; } F[i][j]=now; } } memset(cnt,0,sizeof(cnt)); } int query(int l,int r){ int now=F[bl[l]+1][bl[r]-1]; if (bl[l]==bl[r]){ for (int i=l;i<=r;++i){ if ((++cnt[a[i]])<2) continue; now-=(cnt[a[i]]&1)*2-1; } for (int i=l;i<=r;++i) --cnt[a[i]]; return now; } for (int i=l;i<=r;i=(i==R(bl[l])?L(bl[r]):(i+1))){ if ((++cnt[a[i]])+s[a[i]][bl[r]-1]-s[a[i]][bl[l]]<2) continue; now-=((cnt[a[i]]+s[a[i]][bl[r]-1]-s[a[i]][bl[l]])&1)*2-1; } for (int i=l;i<=r;i=(i==R(bl[l])?L(bl[r]):(i+1))) --cnt[a[i]]; return now; } int main(){ n=read();l=read();int Q=read(),ans=0; for (int i=1;i<=n;++i) a[i]=read(); precompute(); while (Q--){ int x=(read()+ans)%n+1,y=(read()+ans)%n+1; printf("%d\n",ans=query(min(x,y),max(x,y))); } return 0; }