Codeforces 827C DNA Evolution(多维树状数组)

题意:

给定一个只包含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;
}


继续加油~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值