POJ 2778:DNA Sequence
题目大意:给出\(m\)个仅由A,C,T,G组成的字符串和\(n\),求长度为\(n\)的所有仅由A,C,G,T组成的字符串且不包含任意一个给出字符串的个数,\(m\leq10,n\leq2000000000\)
解析:
首先发现字符串很少,我们可以对此构造出AC自动机,则问题转变为了在这个自动机上能匹配多少长度为\(n\)的字符串且不经过单词节点。
我们考虑ban掉所有的单词节点——即让它们“不可通过”,注意,如果一个节点last指针也指向单词节点,那么它也要被ban掉。
那么这个问题就可以通过DP解决,设F[i][j]为长度为j的串结束于节点i有多少种方案,可以通过每次把DP数组乘上一个转移矩阵解决,如果用矩阵快速幂,则时间复杂度为\(O(m^3logn)\)
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
typedef long long LL;
using namespace std;
const int maxn=200+23,csize=4+1;
const int MOD=100000;
int len,n,size,cur,k,v,ch[maxn][csize],x[maxn],f[maxn],last[maxn];
LL m,ans,M[maxn][maxn],Mba[maxn][maxn];
char s[maxn];
bool word[maxn];
void insert(char *s,int n)
{
cur=0;
rep(i,1,n)
{
k=(int)(s[i]-'A'+1);
if (!ch[cur][k]) ch[cur][k]=++size;
cur=ch[cur][k];
}
word[cur]=1;
}
void get_fail()
{
queue<int> Q;
f[0]=0;
rep(i,1,csize-1) if (ch[0][i]) Q.push(ch[0][i]),f[ch[0][i]]=0,last[ch[0][i]]=0;
while (!Q.empty())
{
k=Q.front(); Q.pop();
rep(i,1,csize-1)
{
if (!ch[k][i]) {ch[k][i]=ch[f[k]][i];continue;} else v=ch[k][i],Q.push(v);
cur=f[k];
while (cur && (!ch[cur][i])) cur=f[cur];
f[v]=ch[cur][i];
last[v]=(word[f[v]])?(f[v]):(last[f[v]]);
}
}
rep(i,0,size) if (last[i]) word[i]=1;
}
void mult(LL c[maxn][maxn],LL a[maxn][maxn],LL b[maxn][maxn])
{
LL temp[maxn][maxn];
rep(i,0,size)
rep(j,0,size)
{
temp[i][j]=0;
rep(k,0,size) temp[i][j]=(temp[i][j]+a[i][k]*b[k][j])%MOD;
}
rep(i,0,size) rep(j,0,size) c[i][j]=temp[i][j];
}
void Pow()
{
memset(M,0,sizeof(M));
rep(i,0,size) M[i][i]=1;
len=0;
while (m) x[++len]=(int)(m&1),m>>=1;
dep(k,len,1)
{
mult(M,M,M);
if (x[k]) mult(M,M,Mba);
}
}
int main()
{
scanf("%d%lld",&n,&m);
rep(i,1,n)
{
scanf("%s",s+1);
len=strlen(s+1);
rep(j,1,len)
{
if (s[j]=='C') s[j]='B';
if (s[j]=='T') s[j]='C';
if (s[j]=='G') s[j]='D';
}
insert(s,strlen(s+1));
}
get_fail();
memset(Mba,0,sizeof(Mba));
rep(i,0,size) if (!word[i]) rep(j,1,4) Mba[ch[i][j]][i]++;
Pow();
ans=0;
rep(i,0,size)
if (!word[i]) ans=(ans+M[i][0])%MOD;
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号