【树状数组】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) C. DNA Evolution

题意跟某道我出的等差子序列求最值非常像……

反正询问的长度只有10种,你就建立10批树状数组,每组的公差是确定的,首项不同。

然后询问的时候只需要枚举询问串的每一位,找找这一位对应哪棵树状数组即可。

修改的时候会在10棵树状数组里修改,也是算算修改的位置对应哪一棵即可。

要注意,一共有4种字符,每个树状数组其实分成4个,就只需要单点修改,维护前缀和了……

#include<cstdio>
#include<cstring>
using namespace std;
int n,m,ma[201];
char a[100010];
struct BIT{
	int siz;
	int* d;
	void init(int siz){
		this->siz=siz;
		d=new int[siz];
		memset(d,0,sizeof(int)*siz);
	}
	void Update(int p,int v){for(;p<siz;p+=(p&(-p))) d[p]+=v;}
	int Query(int p){int res=0; for(;p;p-=(p&(-p))) res+=d[p]; return res;}
}T[11][11][4];
int main(){
	ma['A']=0;
	ma['T']=1;
	ma['G']=2;
	ma['C']=3;
	scanf("%s%d",a+1,&m);
	n=strlen(a+1);
	for(int i=1;i<=10;++i){
		for(int j=1;j<=i;++j){
			for(int k=0;k<4;++k){
				T[i][j][k].init(n/i+5);
			}
			for(int k=j,l=1;k<=n;k+=i,++l){
				T[i][j][ma[a[k]]].Update(l,1);
			}
		}
	}
	int op,x,y,z;
	char e[14];
	for(;m;--m){
		scanf("%d%d",&op,&x);
		if(op==1){
			scanf("%s",e);
			for(int i=1;i<=10;++i){
				int x1=x/i+(x%i!=0);
				int x0=x-(x1-1)*i;
				T[i][x0][ma[a[x]]].Update(x1,-1);
				T[i][x0][ma[e[0]]].Update(x1,1);
			}
			a[x]=e[0];
		}
		else{
			int ans=0;
			scanf("%d%s",&y,e+1);
			int len=strlen(e+1);
			for(int i=1;i<=len;++i){
				int X=x+i-1;
				int X1=X/len+(X%len!=0);
				int X0=X-(X1-1)*len;
//				int tmp=X1 + (y-x+1)/len + ((y-x+1)%len>=i) - 1;
				ans+=(T[len][X0][ma[e[i]]].Query(X1 + (y-x+1)/len + ((y-x+1)%len>=i) - 1) -
				T[len][X0][ma[e[i]]].Query(X1-1));
			}
			printf("%d
",ans);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7154045.html