题目:https://www.luogu.org/problemnew/show/P4135
和“历史研究”一样的定义。但因为只能开下一个nsqrt(n)的数组,所以答案记录成第 i 块到第 j 块的。
用数组记录每一块的开始位置和结束位置也许比较好。
不用sta记录要把哪些nm赋0,而是在使用nm之前把要使用的nm手动赋初值也许比较好。
注意预处理 f 数组的时候要开一个tmp,不要直接在 f 上加加减减的,不然第二维一变就要出错了。
然而还是被WA和RE虐。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N=1e5+5,M=320; int n,m,c,a[N],ans,base,bh[N],nm[N]; int bst[M],bed[M],cnt[M][N],f[M][M]; void init() { for(int i=1;i<=bh[n];i++) { int tmp=0,tem=i; memset(nm,0,sizeof nm); bst[i]=(i-1)*base+1;bed[i]=min(n,i*base); for(int j=1;j<=c;j++)cnt[i][j]=cnt[i-1][j]; for(int j=bst[i];j<=bed[i];j++)cnt[i][a[j]]++; for(int j=bst[i];j<=n;j++)//i not bh[i]!!! { nm[a[j]]++; if(nm[a[j]]&1){if(nm[a[j]]!=1)tmp--;}else tmp++; if(j==bed[tem])f[i][tem]=tmp,tem++; // cnt[i][a[j]]++; // if(cnt[i][a[j]]&1){if(cnt[i][a[j]]!=1)tmp--;}else tmp++; // if(j==bed[tem])f[i][tem]=tmp,tem++; // if(cnt[i][a[j]]==1)continue; // if(cnt[i][a[j]]&1)f[i][bh[j]]--;else f[i][bh[j]]++;//不要这样!不然bh[j+1]没有继承bh[j]的! } } } int main() { scanf("%d%d%d",&n,&c,&m);base=sqrt(n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),bh[i]=(i-1)/base+1; init();int x,y; while(m--) { scanf("%d%d",&x,&y); x=(x+ans)%n+1;y=(y+ans)%n+1; if(x>y)swap(x,y); if(bh[y]-bh[x]==0)//!! { ans=0; for(int i=x;i<=y;i++)nm[a[i]]=0; for(int i=x;i<=y;i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } printf("%d\n",ans);continue; } ans=f[bh[x]+1][bh[y]-1];//bh[x]+1!!! if(bh[y]-bh[x]==1)ans=0;// // for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[x]+1][a[i]]-cnt[bh[y]][a[i]]; // for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[x]+1][a[i]]-cnt[bh[y]][a[i]]; for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]]; for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]]; for(int i=bst[bh[y]];i<=y;i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } for(int i=x;i<=bed[bh[x]];i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } printf("%d\n",ans); } return 0; }
这份能AC的代码和上面又有什么不同呢?有毒……
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N=1e5+5,M=320; int n,m,c,a[N],ans,base,bh[N],nm[N]; int bst[M],bed[M],cnt[M][N],f[M][M]; void init(int cr) { int tmp=0,tem=cr; memset(nm,0,sizeof nm); for(int i=bst[cr];i<=n;i++) { nm[a[i]]++; if(nm[a[i]]&1){if(nm[a[i]]!=1)tmp--;}else tmp++; if(i==bed[tem])f[cr][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]),bh[i]=(i-1)/base+1; for(int i=1;i<=bh[n];i++)bst[i]=(i-1)*base+1,bed[i]=min(n,i*base); for(int i=1;i<=bh[n];i++)init(i); for(int i=1;i<=bh[n];i++) { for(int j=1;j<=c;j++)cnt[i][j]=cnt[i-1][j]; for(int j=bst[i];j<=bed[i];j++)cnt[i][a[j]]++; } int x,y; while(m--) { scanf("%d%d",&x,&y); x=(x+ans)%n+1;y=(y+ans)%n+1; if(x>y)swap(x,y); if(bh[y]-bh[x]==0)//!! { ans=0; for(int i=x;i<=y;i++)nm[a[i]]=0; for(int i=x;i<=y;i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } printf("%d\n",ans);continue; } ans=f[bh[x]+1][bh[y]-1];//bh[x]+1!!! if(bh[y]-bh[x]==1)ans=0;// for(int i=bst[bh[y]];i<=y;i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]]; for(int i=x;i<=bed[bh[x]];i++)nm[a[i]]=cnt[bh[y]-1][a[i]]-cnt[bh[x]][a[i]]; for(int i=bst[bh[y]];i<=y;i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } for(int i=x;i<=bed[bh[x]];i++) { nm[a[i]]++; if(nm[a[i]]==1)continue; if(nm[a[i]]&1)ans--;else ans++; } printf("%d\n",ans); } return 0; }