题意:给你一个串k,进行两个操作:
“1 a b”:把a位置的字母换成b
“2 l r s”:求l到r有多少个字母和s匹配,匹配的条件是这样:从l开始无限循环s形成一个串ss,然后匹配ss和指定区间的匹配个数,如图。
思路:用树状数组预处理。因为模板串是不断重复循环的,所以我们可以一个位置一个位置求。对于长len的模板串来说,如果位置i,j满足 i%len == j%len,那么i和j匹配时对模板串来说是一样的(匹配同一个字符)。所以我们定义node[字母][模板串长度][相对位置][位置]来遍历某个位置字符在所有可能的相对位置的情况。
参考:Codeforces - 828E DNA Evolution —— 很多棵树状数组
代码:
#include<stack> #include<vector> #include<queue> #include<set> #include<cstring> #include<string> #include<sstream> #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define ll long long #define ull unsigned long long using namespace std; const int maxn = 100000 + 10; const int seed = 131; const int MOD = 100013; const int INF = 0x3f3f3f3f; char s[maxn]; int h[255]; int node[5][11][11][maxn]; int lowbit(int x){ return x&(-x); } void update(int letter, int x, int val){ for(int i = x; i < maxn; i += lowbit(i)){ for(int len = 1; len <= 10; len++){ node[letter][len][x % len][i] += val; } } } int sum(int letter, int x, int len, int pos){ int ans = 0; for(int i = x; i > 0; i -= lowbit(i)){ ans += node[letter][len][pos][i]; } return ans; } int query(int l, int r, int len, int letter, int pos){ return sum(letter, r, len, pos) - sum(letter, l - 1, len, pos); } int main(){ memset(node, 0 , sizeof(node)); h['A'] = 1, h['G'] = 2, h['C'] = 3, h['T'] = 4; scanf("%s", s + 1); int len = strlen(s + 1); for(int i = 1; i <= len; i++){ update(h[s[i]], i, 1); } int q; scanf("%d", &q); while(q--){ int o,u,v; char ss[12]; scanf("%d", &o); if(o == 1){ scanf("%d%s", &u, ss); update(h[s[u]], u, -1); update(h[ss[0]], u, 1); s[u] = ss[0]; } else{ scanf("%d%d%s", &u, &v, ss); len = strlen(ss); int ans = 0; for(int i = 0; i < len; i++){ ans += query(u, v, len, h[ss[i]], (u + i) % len); } printf("%d ", ans); } } return 0; } /* ATGCATGC 4 2 1 8 ATGC 2 2 6 TTT 1 4 T 2 2 6 TA */