2200专项:C. DNA Evolution(糅合树状数组)

原题: 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);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值