阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 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)∧(wi mod 2=0)(L≤wi≤R)∧(wi mod 2=1)((wi<L)∨(wi>R))∧(wi mod 2=0)((wi<L)∨(wi>R))∧(wi mod 2=1)
其中 ∧ 表示“且”关系,∨ 表示“或”关系,a mod b 表示 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
这道是B题,题目有点绕,仔细分析一下还是挺好懂的,最简单的想法就是根据参数生成S字符串,然后求解的问题就是计算T字符串在S中出现多少次?
我试了这么几个做法:
1.读数据用string,统计用string::find暴力怼,大概只过了不到一半数据,其他超时
2.读数据换成char*,统计用strstr暴力怼,多过了几组数据,最后还有几组超时没过。
3.在2的基础上改进,用KMP算法做,AC
C题和D题题目和这个几乎完全一样,但是数据范围很大,只通过了几个人。。,等我想好再写。
#include <iostream>
#include <string.h>
#define MAX 1000000 + 10
char T[MAX];
char S[MAX];
int next[MAX];
int slen;
int tlen;
void getNext() {
int j, k;
j = 0;
k = -1;
next[0] = -1;
while( j < tlen )
if( k == -1 || T[j] == T[k] )
next[++j] = ++k;
else
k = next[k];
}
int KMP_Count() {
int ans = 0;
int i, j = 0;
if( slen == 1 && tlen == 1 ) {
if( S[0] == T[0] )
return 1;
else
return 0;
}
getNext();
for( i = 0; i < slen; i++) {
while( j > 0 && S[i] != T[j] )
j = next[j];
if( S[i] == T[j] )
j++;
if( j == tlen ) {
ans++;
j = next[j];
}
}
return ans;
}
int main() {
int n, a, b, L, R;
scanf( "%d%d%d%d%d", &n, &a, &b, &L, &R );
scanf( "%s", T );
int cur = 0;
int pre = -1;
for( int i = 0; i < n; i++ ) {
if( i == 0 ) {
cur = b;
}
else {
cur = ( pre + a ) % n;
}
if( cur >= L && cur <= R && cur % 2 == 0 ) S[i] = 'A';
else if( cur >= L && cur <= R && cur % 2 == 1 ) S[i] = 'T';
else if( ( cur < L || cur > R ) && cur % 2 == 0 ) S[i] = 'G';
else if( ( cur < L || cur > R ) && cur % 2 == 1 ) S[i] = 'C';
pre = cur;
}
S[n] = '\0';
slen = strlen( S );
tlen = strlen( T );
printf( "%d\n", KMP_Count() );
return 0;
}