計蒜之道初賽第一場-阿里天池的新任務(簡單)
阿新 • • 發佈:2019-01-31
阿里“天池”競賽平臺近日推出了一個新的挑戰任務:對於給定的一串 DNA 鹼基序列 t,判斷它在另一個根據規則生成的 DNA 鹼基序列 s 中出現了多少次。
首先,定義一個序列 w:
wi={b,(wi−1+a)modn,i=0i>0
接下來,定義長度為 n 的 DNA 鹼基序列 s(下標從 0 開始):
si=⎩⎪⎪⎪⎨⎪⎪⎪⎧A,T,G,C,(L≤wi≤R)∧(wimod2=0)(L≤wi≤R)∧(wimod2=1)((wi<L)∨(wi>R))∧(wimod2=0)((wi<L)∨(wi>R))∧(wimod2=1)
其中 ∧ 表示“且”關係,∨ 表示“或”關係,amodb 表示 a 除以 b 的餘數。
現給定另一個 DNA 鹼基序列 t,以及生成 s 的引數 n,a,b,L,R,求 t 在 s 中出現了多少次。
輸入格式
資料第一行為 5 個整數,分別代表 n,a,b,L,R。第二行為一個僅包含A
、T
、G
、C
的一個序列 t。
資料保證 0<a<n, 0≤b<n, 0≤L≤R<n, ∣t∣≤106,a,n 互質。
對於簡單版本,1≤n≤106;
對於中等版本, 1≤n≤109,a=1;
對於困難版本,1≤n≤109。
輸出格式
輸出一個整數,為 t 在 s 中出現的次數。
樣例說明
對於第一組樣例,生成的 s 為TTTCGGAAAGGCC
。
樣例輸入1
13 2 5 4 9 AGG
樣例輸出1
1
樣例輸入2
103 51 0 40 60 ACTG
樣例輸出2
5
題目大意:中文題,不解釋
解題思路:按要求生成文字串,用kmp模板求匹配數。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN=1e6+100;
LL ans;
int fail[MAXN];
LL n,a,b,L,R;
char ch[MAXN];
char change(int i)
{
LL wi=(b+i*a)%n;
if(wi>=L&&wi<=R)
{
if(wi%2==0) return 'A';
else return 'T';
}else
{
if(wi%2==0) return 'G';
else return 'C';
}
}
void getfail(char *p)
{
int plen=strlen(p);
fail[0]=0,fail[1]=0;//遞推初值
for(int i=1;i<plen;i++)
{
int j=fail[i];
while(j&&p[i]!=p[j])
j=fail[j];
if(p[i]==p[j])
fail[i+1]=j+1;
else
fail[i+1]=0;
}
}
void kmp(char *p)
{
int slen=n;
int plen=strlen(p);
int j=0;//當前結點編號
for(int i=0;i<slen;i++)//文字串當前指標
{
while(j&&p[j]!=change(i))//順著失配邊走,直到可以匹配
j=fail[j];
if(p[j]==change(i))
j++;
if(j==plen)
{
ans++;
//cout<<"find at position "<<i-plen+1<<endl;
j=fail[j];
}
}
}
int main()
{
while(scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&L,&R)!=EOF)
{
scanf("%s",ch);
ans=0;
getfail(ch);
// for(int i=0;i<=strlen(ch);i++)
// {
// cout<<fail[i]<<" ";
// }
// cout<<endl;
kmp(ch);
printf("%lld\n",ans);
}
return 0;