题目链接:hdu 4057 Rescue the Rabbit
题意:
给出一些模式串,每个串有一定的价值,现在构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次。
题解:
由于每个模式串最多统计一次,所以我们要考虑记录是否已经存在该串。
考虑dp[i][j][k]表示当前考虑到i的长度,存在的串的组合为j,在AC自动机上走到了k这个节点的状态。
然后转移一下就能将所有能到达的状态走到。然后取一个最大值就行了。
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 6 const int AC_N=20000,tyn=4; 7 struct AC_automation{ 8 int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 9 inline int getid(char x) 10 { 11 if(x=='A')return 0; 12 if(x=='T')return 1; 13 if(x=='G')return 2; 14 return 3; 15 } 16 void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));} 17 void init(){tot=-1,fail[0]=-1,nw();} 18 void insert(char *s,int idx,int x=0){ 19 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 20 if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot; 21 cnt[x]|=1<<(idx-1); 22 } 23 void build(int head=1,int tail=0){ 24 for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i]; 25 while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++) 26 if(tr[x][i]) 27 { 28 fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i]; 29 cnt[tr[x][i]]|=cnt[fail[tr[x][i]]]; 30 } 31 else tr[x][i]=tr[fail[x]][i]; 32 } 33 }AC; 34 35 int dp[2][1<<10][1001],n,m,val[20],now,U,ans; 36 char s[1000]; 37 38 int getans(int u) 39 { 40 int ans=0; 41 for(int i=1;u;u>>=1,i++)if(u&1)ans+=val[i]; 42 return ans; 43 } 44 45 int main(){ 46 while(~scanf("%d%d",&n,&m)) 47 { 48 now=0,ans=-INT_MAX;AC.init(); 49 F(i,1,n) 50 { 51 scanf("%s%d",s,val+i); 52 AC.insert(s,i); 53 } 54 AC.build(),U=(1<<n)-1; 55 mst(dp[now],0),dp[now][0][0]=1; 56 F(i,1,m) 57 { 58 now^=1,mst(dp[now],0); 59 F(r,0,U)F(j,0,AC.tot) 60 if(dp[now^1][r][j]) 61 F(k,0,3)dp[now][r|AC.cnt[AC.tr[j][k]]][AC.tr[j][k]]=1; 62 } 63 F(j,0,U)F(i,0,AC.tot)if(dp[now][j][i]){ans=max(ans,getans(j));break;} 64 if(ans>=0)printf("%d\n",ans); 65 else puts("No Rabbit after 2012!"); 66 } 67 return 0; 68 }