阿里天池的新任务(简单)【字符串匹配哈希算法】 计蒜客初赛第一场
阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 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
#include <stdio.h> #include <bits/stdc++.h> #define mod 1000000007 typedef long long ll; using namespace std; ll n,a,b,l,r; char vis[1000005],s[1000005]; int main(){ cin>>n>>a>>b>>l>>r; cin>>s; ll w=b; for(int i=0;i<n;i++){ if(l<=w && w<=r){ if(w%2==0) vis[i]='A'; else vis[i]='T'; }else{ if(w%2==0) vis[i]='G'; else vis[i]='C'; } w=(w+a)%n; } int ans=0; int lenb=strlen(s); ll k1=0,k2=0,t=1; //k1计算 s串的哈希值 for(int i=0;i<lenb;i++) k1=k1*mod+s[i]; for(int i=0;i<lenb;i++) t=t*mod; //计算最高位的哈希值 for(int i=0;i<lenb;i++) k2=k2*mod+vis[i]; //计算vis串跟 s长度一样的哈希值 for(int i=0;i<n-lenb+1;i++){ if(k2==k1) ans++; //哈希值相同 说明答案一样 k2=k2*mod+vis[i+lenb]-t*vis[i]; //计算下一个子串的哈希值 } cout<<ans<<endl; return 0; }