BZOJ 2821: 作詩(Poetize)(分塊)
題面
Time Limit: 50 Sec Memory Limit: 128 MB
Submit: 3596 Solved: 1070
[Submit][Status][Discuss]
Description
神犇SJY虐完HEOI之後給傻×LYD出了一題:SHY是T國的公主,平時的一大愛好是作詩。由於時間緊迫,SHY作完詩
之後還要虐OI,於是SHY找來一篇長度為N的文章,閱讀M次,每次只閱讀其中連續的一段[l,r],從這一段中選出一
些漢字構成詩。因為SHY喜歡對偶,所以SHY規定最後選出的每個漢字都必須在[l,r]裡出現了正偶數次。而且SHY認
為選出的漢字的種類數(兩個一樣的漢字稱為同一種)越多越好(為了拿到更多的素材!)。於是SHY請LYD安排選
法。LYD這種傻×當然不會了,於是向你請教……問題簡述:N個數,M組詢問,每次問[l,r]中有多少個數出現正偶
數次。
Input
輸入第一行三個整數n、c以及m。表示文章字數、漢字的種類數、要選擇M次。第二行有n個整數,每個數Ai在[1, c]間,代表一個編碼為Ai的漢字。接下來m行每行兩個整數l和r,設上一個詢問的答案為ans(第一個詢問時ans=0),
令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交換L和R,則本次詢問為[L,R]。
Output
輸出共m行,每行一個整數,第i個數表示SHY第i次能選出的漢字的最多種類數。
Sample Input
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
Sample Output
2
0
0
0
1
HINT
對於100%的資料,1<=n,c,m<=10^5
解題思路
區間出現偶數次的個數,強制線上無法莫隊。那隻好分塊了,剛開始寫了個\(n^{5/3}\)的醜陋分塊,直接\(T\)飛。後來%了%題解發現自己預處理寫醜了,其實可以\(nsqrt(n)\),預處理倒序列舉塊,然後在從塊的右端列舉點。算出\(cnt[i][j]\)表示\(i\)這個數字在前\(j\)塊的出現次數,\(ans[i][j]\)表示\(i,j\)兩塊的答案。詢問時整塊直接呼叫\(ans\)
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN = 100005; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return f?x:-x; } int n,c,m,a[MAXN],siz,cnt[MAXN][320],num,Ans; int bl[MAXN],l[MAXN],r[MAXN],ans[320][320],tmp[MAXN]; int query(int x,int y){ if(bl[x]==bl[y]){ int ret=0; for(int i=x;i<=y;i++){ tmp[a[i]]++; if((tmp[a[i]]&1) && (tmp[a[i]]!=1)) ret--; else if(!(tmp[a[i]]&1)) ret++; } for(int i=x;i<=y;i++) tmp[a[i]]=0; return ret; } int ret=ans[bl[x]+1][bl[y]-1],now; for(int i=x;i<=r[bl[x]];i++) { tmp[a[i]]++;now=cnt[a[i]][bl[y]-1]-cnt[a[i]][bl[x]]+tmp[a[i]]; if(now>1 && (now&1)) ret--; else if(!(now&1)) ret++; } for(int i=l[bl[y]];i<=y;i++){ tmp[a[i]]++;now=cnt[a[i]][bl[y]-1]-cnt[a[i]][bl[x]]+tmp[a[i]]; if(now>1 && (now&1)) ret--; else if(!(now&1)) ret++; } for(int i=x;i<=r[bl[x]];i++) tmp[a[i]]--; for(int i=l[bl[y]];i<=y;i++) tmp[a[i]]--; return ret; } int main(){ n=rd(),c=rd(),m=rd(); siz=sqrt(n)+1;num=n/siz;if(n%siz) num++; for(int i=1;i<=n;i++) a[i]=rd(),bl[i]=(i-1)/siz+1; for(int i=1;i<=num;i++) l[i]=(i-1)*siz+1,r[i]=i*siz; r[num]=n; for(int i=num;i;i--){ int now=0; for(int j=r[i];j;j--){ cnt[a[j]][i]++; if((cnt[a[j]][i]&1) && cnt[a[j]][i]!=1) now--; else if(!(cnt[a[j]][i]&1)) now++; if(bl[j]!=bl[j-1]) ans[bl[j]][i]=now; } } // for(int i=1;i<=num;i++) // for(int j=1;j<=c;j++) // cnt[j][i]+=cnt[j][i-1]; // for(int i=1;i<=num;i++) // for(int j=l[i];j<=r[i];j++) // cnt[a[j]][i]++; // for(int i=1;i<=num;i++) // for(int j=1;j<=c;j++) // cnt[j][i]+=cnt[j][i-1]; // for(int i=1;i<=num;i++) // for(int j=i;j<=num;j++) // for(int k=1;k<=c;k++) // if(cnt[k][j]-cnt[k][i-1]>0 && (!((cnt[k][j]-cnt[k][i-1])&1))) // ans[i][j]++; int L,R; while(m--){ L=rd(),R=rd(); L=(Ans+L)%n+1,R=(Ans+R)%n+1; if(L>R) swap(L,R); Ans=query(L,R); printf("%d\n",Ans); } return 0; }