POJ - 2778 - DNA Sequence
题目链接<http://poj.org/problem?id=2778>
题意:
DNA序列只包含ACTG四个字符,已知一些病毒的DNA序列,问你序列长度为n(1 <= n <=2000000000)且不包含病毒的数量。
题解:
思路与这题的kmp版本基本一样:https://blog.csdn.net/monochrome00/article/details/84072605
AC自动机建立fail数组后本身是一张有向图,直接作为状态进行转移。每个点都有四个方向表示加上四个符号。
如果没有没有包含病毒那么就是可以走的。建立fail指针的时候可以顺便把所有地方的终止符号都打上。
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const ll N=1e2+7;
const ll mod=100000;
ll tot;
map<char,ll>mp;
struct Mat{
ll mat[105][105];
}a;
Mat operator *(Mat a,Mat b){
Mat c;
memset(c.mat,0,sizeof(c.mat));
for(ll k=0;k<tot;k++){
for(ll i=0;i<tot;i++){
if(a.mat[i][k]==0) continue;
for(ll j=0;j<tot;j++){
if(b.mat[k][j]==0) continue;
c.mat[i][j]=(c.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
}
}
}
return c;
}
Mat operator ^(Mat a,ll b){
Mat c;
for(ll i=0;i<tot;i++)
for(ll j=0;j<tot;j++)
c.mat[i][j]=(i==j);
for(ll i=b;i;i>>=1,a=a*a)
if(i&1) c=c*a;
return c;
}
struct Trie {
ll nxt[N][26],fail[N],ed[N];
ll rt;
ll newnode(){
for(ll i=0;i<4;i++)
nxt[tot][i]=-1;
ed[tot++]=0;
return tot-1;
}
void init(){
tot=0;
rt=newnode();
}
void ist(char buf[]){
ll len=strlen(buf);
ll now=rt;
for(ll i=0;i<len;i++){
ll vi=mp[buf[i]];
if(nxt[now][vi]==-1)
nxt[now][vi]=newnode();
now=nxt[now][vi];
}
ed[now]++;
}
void build(){
queue<ll>q;
fail[rt]=rt;
for(ll i=0;i<4;i++){
if(nxt[rt][i]==-1)
nxt[rt][i]=rt;
else{
fail[nxt[rt][i]]=rt;
q.push(nxt[rt][i]);
}
}
while(!q.empty()){
ll now=q.front();
if(ed[fail[now]]) ed[now]=1;
q.pop();
for(ll i=0;i<4;i++){
if(nxt[now][i]==-1)
nxt[now][i]=nxt[fail[now]][i];
else{
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
void bmat(){
memset(a.mat,0,sizeof(a.mat));
for(ll u=0;u<tot;u++){
if(ed[u]) continue;
for(ll i=0;i<4;i++){
ll v=nxt[u][i];
if(ed[v]==0)
a.mat[u][v]++;
}
}
}
}ac;
char buf[N];
int main() {
ll n,m;
ac.init();
mp['A']=0;mp['C']=1;
mp['T']=2;mp['G']=3;
scanf("%lld%lld",&n,&m);
for(ll i=0;i<n;i++){
scanf("%s",buf);
ac.ist(buf);
}
ac.build();
ac.bmat();
a=a^m;
ll ans=0;
for(ll i=0;i<tot;i++)
ans=(ans+a.mat[0][i])%mod;
printf("%lld\n",ans);
return 0;
}
HDU - 2243 - 考研路茫茫——单词情结
题目链接<http://acm.hdu.edu.cn/showproblem.php?pid=2243>
题意:
与上一题很类似。
给出若干个字符串词根,求出长度不超过L,且至少包括一个词根的字符串个数。
题解:
做法也和上一题基本一样,这题需要多加一个求前缀和的运算,只需要修改一下快速幂就行了。
总数是,减去求出来的不包含词根的个数即可。
另外这题要用unsigned long long,并且自带取模。
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
typedef unsigned long long ll;
const ll N=1e2+7;
ll tot;
struct Mat{
ll mat[105][105];
}a;
Mat operator *(Mat a,Mat b){
Mat c;
memset(c.mat,0,sizeof(c.mat));
for(ll k=0;k<tot;k++){
for(ll i=0;i<tot;i++){
if(a.mat[i][k]==0) continue;
for(ll j=0;j<tot;j++){
if(b.mat[k][j]==0) continue;
c.mat[i][j]=(c.mat[i][j]+(a.mat[i][k]*b.mat[k][j]));
}
}
}
return c;
}
Mat operator +(Mat a,Mat b){
Mat c;
for(ll i=0;i<tot;i++)
for(ll j=0;j<tot;j++)
c.mat[i][j]=(a.mat[i][j]+b.mat[i][j]);
return c;
}
Mat operator ^(Mat a,ll b){
Mat c,t=a;
memset(c.mat,0,sizeof(c.mat));
for(ll i=b;i;i>>=1,a=a*a){
if(i&1) c=t+c*a;
t=t+t*a;
}
return c;
}
struct Trie {
ll nxt[N][26],fail[N],ed[N];
ll rt;
ll newnode(){
for(ll i=0;i<26;i++)
nxt[tot][i]=-1;
ed[tot++]=0;
return tot-1;
}
void init(){
tot=0;
rt=newnode();
}
void ist(char buf[]){
ll len=strlen(buf);
ll now=rt;
for(ll i=0;i<len;i++){
ll vi=buf[i]-'a';
if(nxt[now][vi]==-1)
nxt[now][vi]=newnode();
now=nxt[now][vi];
}
ed[now]++;
}
void build(){
queue<ll>q;
fail[rt]=rt;
for(ll i=0;i<26;i++){
if(nxt[rt][i]==-1)
nxt[rt][i]=rt;
else{
fail[nxt[rt][i]]=rt;
q.push(nxt[rt][i]);
}
}
while(!q.empty()){
ll now=q.front();
if(ed[fail[now]]) ed[now]=1;
q.pop();
for(ll i=0;i<26;i++){
if(nxt[now][i]==-1)
nxt[now][i]=nxt[fail[now]][i];
else{
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
void bmat(){
memset(a.mat,0,sizeof(a.mat));
for(ll u=0;u<tot;u++){
if(ed[u]) continue;
for(ll i=0;i<26;i++){
ll v=nxt[u][i];
if(ed[v]==0)
a.mat[u][v]++;
}
}
}
}ac;
char buf[N];
ll qpow(ll a,ll b){
ll ans=0;
ll t=a;
for(ll i=b;i;i>>=1,a=a*a){
if(i&1) ans=t+ans*a;
t=t+t*a;
}
return ans;
}
int main() {
ll n,m;
while(scanf("%llu%llu",&n,&m)!=EOF){
ac.init();
for(ll i=0;i<n;i++){
scanf("%s",buf);
ac.ist(buf);
}
ac.build();
ac.bmat();
a=a^m;
ll ans=qpow(26,m);
for(ll i=0;i<tot;i++)
ans=ans-a.mat[0][i];
printf("%llu\n",ans);
}
return 0;
}