题目链接:hdu_2296_Ring
题意:
有m个字符串,每个字符串有一个价值,现在让你组成一个不超过n长度的字符串,使得价值最大
题解:
很明显是在AC自动机上的DP,设dp[i][j]表示当前长度为i,AC自动机上匹配到j这个节点的最大价值,这里要求字典序最小,处理的稍微复杂一点,具体看代码
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int AC_N=110*20,tyn=26;//数量乘串长,类型数 6 struct AC_automation{ 7 int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 8 inline int getid(char x){return x-'a';} 9 void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));} 10 void init(){tot=-1,fail[0]=-1,nw();} 11 void insert(char *s,int val,int x=0){ 12 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 13 if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot; 14 cnt[x]=val;//串尾标记 15 } 16 void build(int head=1,int tail=0){ 17 for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i]; 18 while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++) 19 if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i],cnt[tr[x][i]]+=cnt[tr[fail[x]][i]]; 20 else tr[x][i]=tr[fail[x]][i]; 21 } 22 }AC; 23 24 char s[110][20]; 25 string path[51][AC_N]; 26 int t,n,m,x,dp[51][AC_N]; 27 28 void fuck(int ans=0) 29 { 30 memset(dp,-1,sizeof(dp)),dp[0][0]=0; 31 F(i,0,n)F(j,0,AC.tot)path[i][j].clear(); 32 F(i,0,n-1)F(j,0,AC.tot)if(dp[i][j]!=-1)F(k,0,25) 33 { 34 int now=AC.tr[j][k]; 35 if(dp[i][j]+AC.cnt[now]>dp[i+1][now]) 36 { 37 dp[i+1][now]=dp[i][j]+AC.cnt[now]; 38 path[i+1][now]=path[i][j]+(char)(k+'a'); 39 }else if(dp[i][j]+AC.cnt[now]==dp[i+1][now]&&path[i][j]+(char)(k+'a')<path[i+1][now]) 40 path[i+1][now]=path[i][j]+(char)(k+'a'); 41 } 42 F(i,1,n)F(j,0,AC.tot)ans=max(ans,dp[i][j]); 43 if(ans==0){puts("");return;} 44 string str=" "; 45 F(i,1,n)F(j,0,AC.tot)if(dp[i][j]==ans&&(str==" "||(path[i][j].size()<str.size()||(path[i][j].size()==str.size()&&path[i][j]<str))))str=path[i][j]; 46 cout<<str<<endl; 47 } 48 49 int main() 50 { 51 scanf("%d",&t); 52 while(t--) 53 { 54 scanf("%d%d",&n,&m); 55 AC.init(); 56 F(i,1,m)scanf("%s",s[i]); 57 F(i,1,m)scanf("%d",&x),AC.insert(s[i],x); 58 AC.build(),fuck(); 59 } 60 return 0; 61 }