题意:
给定一个只包含A,T,C,G的字符串,有如下两种操作
1)修改一个点的字母
2)给定区间L, R和一个字符串e (strlen(e) <=10),组成一个足够区间长度的由若干个e重复组成的新串,eee...,问L,R区间中有几个位置对应的字母跟这个新的字符串对应的相同。
思路:
因为e的长度最多才10,所以对于一个字母,它最多有10个不同的起始位置,10个不同的长度进行重复,所以建立一个4*10*10的树状数组,再维护就可以了。
注意维护和查询时候的细节就好了,并不难。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
char s[maxn], e[11];
map<char, int> mp;
int c[11][11][4][maxn], cnt[11][11];
int n, len;
int lowbit(int x) {return x & -x;}
void update(int x, int y, int z, int pos, int val)
{
while(pos <= cnt[x][y])
{
c[x][y][z][pos] += val;
pos += lowbit(pos);
}
}
int query(int x, int y, int z, int pos)
{
int ans = 0;
while(pos)
{
ans += c[x][y][z][pos];
pos -= lowbit(pos);
}
return ans;
}
void init()
{
memset(c, 0, sizeof c);
mp['A'] = 0, mp['T'] = 1, mp['G'] = 2, mp['C'] = 3;
len = strlen(s+1);
for(int i = 1; i <= min(10, len); ++i)
for(int j = i; j <= 10; ++j)
{
cnt[i][j] = (len-i)/j+1;
for(int k = 0; i+k*j <= len; ++k)
{
if(s[i+k*j] == 'A') update(i, j, 0, k+1, 1);
if(s[i+k*j] == 'T') update(i, j, 1, k+1, 1);
if(s[i+k*j] == 'G') update(i, j, 2, k+1, 1);
if(s[i+k*j] == 'C') update(i, j, 3, k+1, 1);
}
}
}
void change(int t, char e)
{
int mmp = min(min(10, len), t);
for(int i = 1; i <= mmp; ++i)
for(int j = i; j <= 10; ++j)
{
if((t-i)%j == 0)
{
int k = (t-i)/j;
update(i, j, mp[s[t]], k+1, -1);
update(i, j, mp[e], k+1, 1);
}
}
s[t] = e;
}
int main()
{
ios::sync_with_stdio(0);
cin >> s+1;
init();
cin >> n;
int key, x, l, r;
for(int i = 1; i <= n; ++i)
{
cin >> key;
if(key == 1)
{
cin >> x;
cin >> e;
change(x, e[0]);
}
if(key == 2)
{
cin >> l >> r;
cin >> e+1;
int ans = 0, elen = strlen(e+1);
for(int j = 1; l+j-1 <= r && j <= elen; ++j)
{
int start = (l+j-1)%elen;
if(start == 0) start = elen;
if(l-1-start >= 0)
{
int ll = (l-1-start)/elen+1;
ans -= query(start, elen, mp[e[j]], ll);
}
if(r-start >= 0)
{
int rr = (r-start)/elen+1;
ans += query(start, elen, mp[e[j]], rr);
}
}
cout << ans << endl;
}
}
return 0;
}
继续加油~