2017 计蒜之道 初赛 第一场 阿里天池的新任务(简单)(KMP)
2017-05-23 16:06
302 查看
题目:
18.8%
2000ms
262144K
阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 tt,判断它在另一个根据规则生成的
DNA 碱基序列 ss 中出现了多少次。
首先,定义一个序列 ww:
\displaystyle
w_{i} = \begin{cases}b, & i = 0\\(w_{i-1} + a) \mod n, & i > 0\end{cases}wi={b,(wi−1+a)modn,i=0i>0
接下来,定义长度为 nn 的
DNA 碱基序列 ss(下标从 00 开始):
\displaystyle
s_{i} = \begin{cases}A , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\T , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\\G , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\C , & ((w_{i} < L) \lor (w_{i} > R)) \land
(w_{i}\ \mathrm{mod}\ 2 = 1)\end{cases}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)
其中 \land∧ 表示“且”关系,\lor∨ 表示“或”关系,a\
\mathrm{mod}\ ba mod b 表示 aa 除以 bb 的余数。
现给定另一个 DNA 碱基序列 tt,以及生成 ss 的参数 n
, a , b , L , Rn,a,b,L,R,求 tt 在 ss 中出现了多少次。
, a , b , L , Rn,a,b,L,R。第二行为一个仅包含
数据保证 0
< a < n,0<a<n, 0
\le b < n,0≤b<n, 0
\le L \le R < n,0≤L≤R<n, |t|
\le 10^{6}∣t∣≤106,a,na,n 互质。
对于简单版本,1
\leq n \leq 10^{6}1≤n≤106;
对于中等版本,1
\leq n \leq 10^{9}, a = 11≤n≤109,a=1;
对于困难版本,1
\leq n \leq 10^{9}1≤n≤109。
思路:
按照题意构造主串,然后剩下的是一个KMP板子。。。
我WA了将近20发。。换了无数种方法,想了无数种可能。。。
最后发现。。。。我的next数组开成char型了。。。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N (1000020)
#define ll long long
using namespace std;
char s
,t
;
ll nxt
;
ll n,a,b,L,R,len_s,len_t;
char get_s(ll i)
{
ll wi=(b+i*a)%n;
if(wi>=L&&wi<=R)
{
if(wi&1)
return 'T';
else
return 'A';
}
else
{
if(wi&1)
return 'C';
else
return 'G';
}
}
void getnext()
{
ll j=0,k=-1;
nxt[0]=-1;
while(j<len_t)
{
if(k==-1||t[j]==t[k])
nxt[++j]=++k;
else
k=nxt[k];
}
}
ll kmp_cnt()
{
ll ans=0;
ll i,j=0;
if(len_s==1&&len_t==1)
{
if(s[0]==t[0])
return 1;
else
return 0;
}
getnext();
for(ll i=0;i<len_s;i++)
{
while(j>0&&s[i]!=t[j])
j=nxt[j];
if(s[i]==t[j])
j++;
if(j==len_t)
{
ans++;
j=nxt[j];
}
}
return ans;
}
int main()
{
while(~scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&L,&R))
{
scanf("%s",t);
len_t=strlen(t);
len_s=n;
for(ll i=0;i<n;i++)
s[i]=get_s(i);
printf("%lld\n",kmp_cnt());
}
return 0;
}
18.8%
2000ms
262144K
阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 tt,判断它在另一个根据规则生成的
DNA 碱基序列 ss 中出现了多少次。
首先,定义一个序列 ww:
\displaystyle
w_{i} = \begin{cases}b, & i = 0\\(w_{i-1} + a) \mod n, & i > 0\end{cases}wi={b,(wi−1+a)modn,i=0i>0
接下来,定义长度为 nn 的
DNA 碱基序列 ss(下标从 00 开始):
\displaystyle
s_{i} = \begin{cases}A , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\T , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\\G , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\C , & ((w_{i} < L) \lor (w_{i} > R)) \land
(w_{i}\ \mathrm{mod}\ 2 = 1)\end{cases}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)
其中 \land∧ 表示“且”关系,\lor∨ 表示“或”关系,a\
\mathrm{mod}\ ba mod b 表示 aa 除以 bb 的余数。
现给定另一个 DNA 碱基序列 tt,以及生成 ss 的参数 n
, a , b , L , Rn,a,b,L,R,求 tt 在 ss 中出现了多少次。
输入格式
数据第一行为 55 个整数,分别代表 n, a , b , L , Rn,a,b,L,R。第二行为一个仅包含
A、
T、
G、
C的一个序列 tt。
数据保证 0
< a < n,0<a<n, 0
\le b < n,0≤b<n, 0
\le L \le R < n,0≤L≤R<n, |t|
\le 10^{6}∣t∣≤106,a,na,n 互质。
对于简单版本,1
\leq n \leq 10^{6}1≤n≤106;
对于中等版本,1
\leq n \leq 10^{9}, a = 11≤n≤109,a=1;
对于困难版本,1
\leq n \leq 10^{9}1≤n≤109。
输出格式
输出一个整数,为 tt 在 ss 中出现的次数。样例说明
对于第一组样例,生成的 ss 为TTTCGGAAAGGCC。
样例输入1
13 2 5 4 9 AGG
样例输出1
1
样例输入2
103 51 0 40 60 ACTG
样例输出2
5
思路:
按照题意构造主串,然后剩下的是一个KMP板子。。。
我WA了将近20发。。换了无数种方法,想了无数种可能。。。
最后发现。。。。我的next数组开成char型了。。。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N (1000020)
#define ll long long
using namespace std;
char s
,t
;
ll nxt
;
ll n,a,b,L,R,len_s,len_t;
char get_s(ll i)
{
ll wi=(b+i*a)%n;
if(wi>=L&&wi<=R)
{
if(wi&1)
return 'T';
else
return 'A';
}
else
{
if(wi&1)
return 'C';
else
return 'G';
}
}
void getnext()
{
ll j=0,k=-1;
nxt[0]=-1;
while(j<len_t)
{
if(k==-1||t[j]==t[k])
nxt[++j]=++k;
else
k=nxt[k];
}
}
ll kmp_cnt()
{
ll ans=0;
ll i,j=0;
if(len_s==1&&len_t==1)
{
if(s[0]==t[0])
return 1;
else
return 0;
}
getnext();
for(ll i=0;i<len_s;i++)
{
while(j>0&&s[i]!=t[j])
j=nxt[j];
if(s[i]==t[j])
j++;
if(j==len_t)
{
ans++;
j=nxt[j];
}
}
return ans;
}
int main()
{
while(~scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&L,&R))
{
scanf("%s",t);
len_t=strlen(t);
len_s=n;
for(ll i=0;i<n;i++)
s[i]=get_s(i);
printf("%lld\n",kmp_cnt());
}
return 0;
}
相关文章推荐
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 2017 计蒜之道 初赛 第一场 阿里的天池任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 计蒜客 2017 初赛第一场 B. 阿里天池的新任务(简单)
- 2017计蒜之道 初赛第一场 阿里天池的新任务(简单)
- [数论] 2017 计蒜之道 初赛 第一场 阿里天池的新任务
- 计蒜之道 初赛第一场B 阿里天池的新任务(简单)
- 计蒜客 阿里天池的新任务(简单)KMP轻松水过
- 2017 计蒜客初赛 阿里天池的新任务(KMP算法)
- 2017 计蒜之道 初赛 第一场 B阿里天池的新任务(简单)