原题: http://codeforces.com/problemset/problem/827/C
题意:
给出一个AGTC组成字符串,操作为改变一个位置的字符,查询为 l l l到 r r r,给出一个字符串,长度小于等于10,问区间内的串与这个串的无限循环有多少个位置相同。
解析:
因为给出的串长度最多只有10,所以可以存下循环节为i,某个位置字符为c的一个树状数组。
举个例子,若查询串为abc(已经转化成下标为1开始),那么我们应该找 3 k + 1 3k+1 3k+1的位置有多少个a。
那么数组应该是 d p [ 查 询 串 长 度 ] [ 查 询 串 的 位 置 ] [ 原 串 的 位 置 ] [ 字 符 种 类 ] dp[查询串长度][查询串的位置][原串的位置][字符种类] dp[查询串长度][查询串的位置][原串的位置][字符种类],例如1~100查询abc中的a应该是 d p [ 3 ] [ 100 ] [ 1 ] [ a ] dp[3][100][1][a] dp[3][100][1][a],我们发现这样树状数组中只使用了1,4,7,10,所以可以合并成 d p [ 查 询 串 长 度 ] [ 原 串 的 位 置 ] [ 字 符 种 类 ] dp[查询串长度][原串的位置][字符种类] dp[查询串长度][原串的位置][字符种类]。
处理时 3 k + 1 3k+1 3k+1的下一个位置是 3 ( k + l o w b i t ( k ) ) + 1 3(k+lowbit(k))+1 3(k+lowbit(k))+1
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=100009;
inline int idx(char x){
switch(x){
case 'A':return 0;
case 'T':return 1;
case 'G':return 2;
default :return 3;
}
}
char x[maxn];
int Len;
int tr[10][maxn][4];
void update(int len,int p,int id,int val){
int c=(p+len-1)/len,r=p%len;
if(r==0)r=len;
while(1){
p=(c-1)*len+r;
if(p>Len)break;
tr[len][p][id]+=val;
c+=c&-c;
}
}
int query(int len,int id,int p){
int c=(p+len-1)/len,r=p%len;
if(r==0)r=len;
int res=0;
while(1){
p=(c-1)*len+r;
if(p<=0)break;
res+=tr[len][p][id];
c-=c&-c;
}
return res;
}
int main(){
scanf("%s",x+1);
Len=strlen(x+1);
for(int i=1;i<=10;i++){
for(int j=1;j<=Len;j++){
update(i,j,idx(x[j]),1);
}
}
int q;scanf("%d",&q);
char tmp[13],tmp2[13];
while(q--){
int f;scanf("%d",&f);
if(f==1){
int pos;
scanf("%d%s",&pos,tmp);
int id1=idx(x[pos]);
int id2=idx(tmp[0]);
x[pos]=tmp[0];
for(int i=1;i<=10;i++){
update(i,pos,id1,-1);
update(i,pos,id2,1);
}
}
else{
int l,r;
scanf("%d%d%s",&l,&r,tmp2+1);
int len=strlen(tmp2+1);
for(int i=1;i<=len;i++){
int to=((i-(l-1))%len+len)%len;
if(to==0)to=len;
tmp[i]=tmp2[to];
}
tmp[len+1]='\0';
int ans=0;
for(int i=1;i<=len;i++){
int ll=l-1,rr=r;
while(rr%len!=i%len&&rr>0)rr--;
if(rr>0)
ans+=query(len,idx(tmp[i]),rr);
while(ll%len!=i%len&&ll>0)ll--;
if(ll>0)
ans-=query(len,idx(tmp[i]),ll);
//printf("第%d位匹配后ans为%d\n",i,ans);
}
printf("%d\n",ans);
}
}
}