zoukankan      html  css  js  c++  java
  • bzoj2821: 作诗(Poetize)

    传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2821

    思路:分块大法好。。。

    分成sqrt(n)块,先预处理出连续的块的答案,f[i][j]表示第i块到第j块的答案。

    然后再开一个前缀和数组sum[i][j]表示前i个块第j种字符出现的次数。

    对于一组询问[l,r],先得出连续的块的答案。

    对于分散的两端的块,暴力考虑每个数对答案的贡献即可。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=100010,maxb=320;
    using namespace std;
    int n,c,m,sum[maxb][maxn],f[maxb][maxb],a[maxn],sz,cnt,bel[maxn],l[maxn],r[maxn],tsum[maxn],ans,tmp[maxn];
    
    void work(){
    	int x,y,L,R;scanf("%d%d",&x,&y);
    	x=(x+ans)%n+1,y=(y+ans)%n+1,ans=0;
    	if (x>y) swap(x,y);
    	//printf("%d %d
    ",x,y);
    	L=bel[x],R=bel[y];
    	if (L==R){
    		for (int i=x;i<=y;i++) tsum[a[i]]=0;
    		for (int i=x;i<=y;i++)
    			if ((++tsum[a[i]])!=1)
    				ans+=(tsum[a[i]]&1)?-1:1;
    	}
    	else{
    		ans=f[L+1][R-1];
    		//printf("ans%d %d %d
    ",L,R,ans);
    		for (int i=x;i<=r[L];i++) tsum[a[i]]=sum[R-1][a[i]]-sum[L][a[i]];
    		for (int i=l[R];i<=y;i++) tsum[a[i]]=sum[R-1][a[i]]-sum[L][a[i]];
    		//for (int i=1;i<=c;i++) printf("tsum%d
    ",tsum[i]);
    		for (int i=x;i<=r[L];i++)
    			if (++tsum[a[i]]!=1)
    				ans+=(tsum[a[i]]&1)?-1:1;
    		for (int i=l[R];i<=y;i++)
    			if (++tsum[a[i]]!=1)
    				ans+=(tsum[a[i]]&1)?-1:1;
    	}
    	printf("%d
    ",ans);
    }
    
    int main(){
    	scanf("%d%d%d",&n,&c,&m),sz=sqrt(n),cnt=n/sz+(n%sz!=0);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for (int i=1;i<=n;i++) bel[i]=(i-1)/sz+1;
    	for (int i=1;i<=n;i++){r[bel[i]]=i;if (!l[bel[i]]) l[bel[i]]=i;}
    	for (int i=1;i<=cnt;i++){
    		for (int j=1;j<=c;j++) sum[i][j]=sum[i-1][j];
    		for (int j=l[i];j<=r[i];j++) sum[i][a[j]]++;
    	}
    	for (int i=1;i<=cnt;i++){
    		for (int j=1;j<=c;j++) tsum[j]=0;int tmp=0;
    		for (int j=i;j<=cnt;j++){
    			for (int k=l[j];k<=r[j];k++)
    				if (tsum[a[k]]++) tmp+=(tsum[a[k]]&1)?-1:1;
    			f[i][j]=tmp;
    		}
    	}
    	//for (int i=1;i<=cnt;i++) printf("%d %d
    ",l[i],r[i]);
    	/*for (int i=1;i<=cnt;i++,puts(""))
    		for (int j=1;j<=cnt;j++)
    			printf("%d ",f[i][j]);*/
    	for (int i=1;i<=m;i++) work();
    	return 0;
    }


  • 相关阅读:
    85. Maximal Rectangle
    120. Triangle
    72. Edit Distance
    39. Combination Sum
    44. Wildcard Matching
    138. Copy List with Random Pointer
    91. Decode Ways
    142. Linked List Cycle II
    异或的性质及应用
    64. Minimum Path Sum
  • 原文地址:https://www.cnblogs.com/thythy/p/5493539.html
Copyright © 2011-2022 走看看