1. 程式人生 > 其它 >【CF827C DNA Evolution】題解

【CF827C DNA Evolution】題解

題目連結

題目

DNA鏈由核苷酸組成。有四種類型的核苷酸:“A”,“T”,“G”,“C”。 DNA鏈是核苷酸序列。科學家決定追蹤一種稀有物種的進化,它最初的DNA鏈為s。

物種的進化被描述為DNA的一系列變化。每個變化都是某些核苷酸的變化,例如,DNA鏈“AAGC”中可能發生以下變化:第二個核苷酸可以變為“T”,然後變成“ATGC”。

科學家們知道DNA鏈的某些片段會受到某些未知感染的影響。這些感染可以被表示為核苷酸序列。科學家們對引起變化的感染十分感興趣。因此,他們有時想知道某些感染對某些DNA片段的影響的價值。價值是這樣計算的:

用字串e代表表示感染的核苷酸序列,科學家們對DNA序列從l到r(包括端點)的片段感興趣。

把字串eee……的字首(即字串e重複許多次組成的字串)寫在字串s從l到r(包括端點)的片段下邊。

感染對DNA片段的價值是感染與DNA片段在l到r區間內,相同位置相同的核苷酸的數量。

作為開發者,Innokenty也對生物資訊學感興趣,因此科學家們向他求助。 Innokenty正在忙著準備VK杯,所以他決定將問題交給參賽者們。來幫幫科學家們吧!

Everyone knows that DNA strands consist of nucleotides. There are four types of nucleotides: "A", "T", "G", "C". A DNA strand is a sequence of nucleotides. Scientists decided to track evolution of a rare species, which DNA strand was string $ s $ initially.

Evolution of the species is described as a sequence of changes in the DNA. Every change is a change of some nucleotide, for example, the following change can happen in DNA strand "AAGC": the second nucleotide can change to "T" so that the resulting DNA strand is "ATGC".

Scientists know that some segments of the DNA strand can be affected by some unknown infections. They can represent an infection as a sequence of nucleotides. Scientists are interested if there are any changes caused by some infections. Thus they sometimes want to know the value of impact of some infection to some segment of the DNA. This value is computed as follows:

  • Let the infection be represented as a string $ e $ , and let scientists be interested in DNA strand segment starting from position $ l $ to position $ r $ , inclusive.
  • Prefix of the string $ eee... $ (i.e. the string that consists of infinitely many repeats of string $ e $ ) is written under the string $ s $ from position $ l $ to position $ r $ , inclusive.
  • The value of impact is the number of positions where letter of string $ s $ coincided with the letter written under it.

Being a developer, Innokenty is interested in bioinformatics also, so the scientists asked him for help. Innokenty is busy preparing VK Cup, so he decided to delegate the problem to the competitors. Help the scientists!

思路

發現 \(|e|\leqslant 10\),猜測其為突破口。

以下圖為例,上面為原串,下面為詢問區間\(|e|\)迴圈節長度(此時長度為3)

考慮 \(e\) 串中第 \(i\) 位對答案的貢獻,假設 \(e_i\) 在原串中第一次對應的位置(先不考慮是否匹配)\(j\) 出現,則後面出現 \(e_i\) 的位置 \(k\) 必然滿足 \(k\bmod|e|=j\bmod|e|\)。如果考慮匹配,只需分四類討論,統計區間匹配個數,用三維樹狀陣列維護。

樹狀陣列其中一維為字母,現在討論剩下兩維。

綜上所述,考慮原串中每個位置 \(i\),把它拆成 \(10\) ,列舉 \(p\) 使得 {$p\in N | 1\leqslant p\leqslant 10 $},求 \(i\bmod p=x\),則樹狀陣列另外兩維分別為 \(p\)\(x\)。這樣子詢問只需列舉 \(|e|\) 即可。

總時間複雜度 \(O(q\times \log n\times 10)\)

Code

// Problem: CF827C DNA Evolution
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF827C
// Memory Limit: 500 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
// #define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 100010
//#define M
//#define mo
int n, m, i, j, k, T; 
int cnt[11][11][5][N]; 
int mp[150], q, l, r, x, y, e, o, ans; 
char s[N], t[20], c; 

void add(int cnt[], int x, int y)
{
	while(x<=n)
	{
		cnt[x]+=y; 
		x+=x&-x; 
	}
}

int qiu(int cnt[], int x)
{
	int ans=0; 
	while(x)
	{
		ans+=cnt[x]; 
		x-=x&-x; 
	}
	return ans; 
}

signed main()
{
//	freopen("tiaoshi.in","r",stdin);
//	freopen("tiaoshi.out","w",stdout);
	mp['A']=1; mp['C']=2; mp['T']=3; mp['G']=4; 
	scanf("%s", s+1); 
	n=strlen(s+1); 
	for(i=1; i<=n; ++i)
		for(j=1; j<=10; ++j)
			add(cnt[j][i%j][mp[(int)s[i]]], i, 1); 
	q=read(); 
	while(q--)
	{
		o=read(); 
		if(o==1)
		{
			x=read(); scanf("%c", &c); 
			for(j=1; j<=10; ++j)
				add(cnt[j][x%j][mp[(int)s[x]]], x, -1); 
			s[x]=c; 
			for(j=1; j<=10; ++j)
				add(cnt[j][x%j][mp[(int)s[x]]], x, 1); 
		}
		if(o==2)
		{
			l=read(); r=read(); 
			scanf("%s", t+1); 
			m=strlen(t+1); ans=0; 
			for(i=1, j=l; i<=m && j<=r; ++i, ++j) 
				ans+=(qiu(cnt[m][j%m][mp[(int)t[i]]], r)
				-qiu(cnt[m][j%m][mp[(int)t[i]]], l-1)); 
			printf("%d\n", ans); 
		}
	}
	return 0;
}

總結

這道題的切入點是 \(|e|\leq 10\),思考方向是 \(|e|\) 從1開始思考,再想2、3。

對於題目中資料特殊的,我們可以把這個特殊資料從小開始思考,易發現性質,來完成此類題目。