题意:
给你一个只包含'A', 'T', 'G', 'C'的字符串,q次操作,有两种操作:
1 x ch : 将x位置改成ch
2 l r e:e为一个长度不超过10的字符串,问eeeee....与字符串的子串[l, r]有多少个匹配的字符(先将e的开头和l对齐)
思路:
一共就4种字符,可以分别考虑每个字符,e长度最大才10,可以分别考虑不同长度的e。
假设e长为len, 那么i , i+len ,i+len*2, i+len*3.....一定是去对应e的相同位置,pos%len相同可以归为一组,一共最多10个位置,所以可以开
10*10*4的树状数组,tree[x][y][z]记录的是e长度为y的对应位置为x的字符为z的数量。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int tree[12][12][5][maxn], id[256];
char str[maxn], tmp[15];
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int y, int z, int pos, int val)
{
while(pos < maxn)
{
tree[x][y][z][pos] += val;
pos += lowbit(pos);
}
}
int query(int x, int y, int z, int pos)
{
int sum = 0;
while(pos)
{
sum += tree[x][y][z][pos];
pos -= lowbit(pos);
}
return sum;
}
int main(void)
{
id['A'] = 0, id['T'] = 1, id['G'] = 2, id['C'] = 3;
while(cin >> str)
{
memset(tree, 0, sizeof(tree));
int len = strlen(str);
for(int i = 1; i <= len; i++)
for(int j = 1; j <= 10; j++)
update(i%j, j, id[str[i-1]], i, 1);
int q;
scanf("%d", &q);
while(q--)
{
int cmd, x, y;
char ch;
scanf("%d%d", &cmd, &x);
if(cmd == 1)
{
scanf(" %c", &ch);
for(int j = 1; j <= 10; j++)
{
update(x%j, j, id[ch], x, 1);
update(x%j, j, id[str[x-1]], x, -1);
}
str[x-1] = ch;
}
else
{
scanf("%d %s", &y, tmp);
int len = strlen(tmp);
int ans = 0;
for(int i = 1; i <= len; i++)
ans += query((x+i-1)%len, len, id[tmp[i-1]], y)-query((x+i-1)%len, len, id[tmp[i-1]], x-1);
printf("%d\n", ans);
}
}
}
return 0;
}
/*
ATGCATGC
4
2 1 8 ATGC
2 2 6 TTT
1 4 T
2 2 6 TA
8
2
4
*/