[hdu2296]Ring(AC自动机+dp)

题意:你M个单词构成一个词典,每个单词有一个权值(单词出现多次算多个权值),现在要你构造一个不超过长度N的字符串,使得该字符串权值最大。如果出现多个答案,输出最短的,如果依然有多解,输出字典序最小的。

解题关键:最典型的AC自动机上跑dp。

令$dp[i][j] = x$表示走了i步到达j点的最大价值,则

转移方程:$dp[i][j] = \max (dp[i][j],dp[i-1][k] + val[j])$

$val[i]$代表以某前缀的价值总和。

注意这里是多对多的关系,需用从遍历起点时更新后面的点。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<queue>
  8 #include<string>
  9 using namespace std;
 10 typedef long long ll;
 11 const int N=26;
 12 const int MAXN=1101;
 13 int m,n;
 14 int mod=100000;
 15 int val[MAXN];
 16 int dp[52][1101];
 17 string path[52][1101];
 18 struct Trie{
 19     int Next[MAXN][N],Fail[MAXN],root,tot;
 20     int End[MAXN];
 21     int newnode(){
 22         for(int i=0;i<N;i++) Next[tot][i]=-1;
 23         End[tot++]=0;
 24         return tot-1;
 25     }
 26     void init(){
 27         tot=0;
 28         root=newnode();
 29     }
 30     
 31     void insert(char buf[],int x){
 32         int len=(int)strlen(buf),now=root,k;
 33         for(int i=0;i<len;i++){
 34             k=buf[i]-'a';
 35             if(Next[now][k]==-1)  Next[now][k]=newnode();
 36             now=Next[now][k];
 37         }
 38         End[now]=x;
 39     }
 40     
 41     void build(){
 42         queue<int>que;
 43         Fail[root]=root;
 44         for(int i=0;i<N;i++){
 45             if(Next[root][i]==-1) Next[root][i]=root;
 46             else{
 47                 Fail[Next[root][i]]=root;
 48                 que.push(Next[root][i]);
 49             }
 50         }
 51         while(!que.empty()){
 52             int now=que.front();
 53             que.pop();
 54                End[now]+=End[Fail[now]];//此题可重复计算,所以要加
 55             for(int i=0;i<N;i++){
 56                 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i];
 57                 else{
 58                     Fail[Next[now][i]]=Next[Fail[now]][i];
 59                     que.push(Next[now][i]);
 60                 }
 61             }
 62         }
 63     }
 64     
 65     void solve(int n){
 66         memset(dp,-1,sizeof dp);
 67         dp[0][0]=0;
 68         for(int i=0;i<n;i++){
 69             for(int j=0;j<tot;j++){
 70                 if(dp[i][j]==-1) continue;
 71                 for(int k=0;k<26;k++){
 72                     int u=Next[j][k];
 73                     if(dp[i][j]+End[u]>dp[i+1][u]){
 74                         dp[i+1][u]=dp[i][j]+End[u];
 75                         path[i+1][u]=path[i][j]+char(k+'a');
 76                     }else if(dp[i][j]+End[u]==dp[i+1][u]){
 77                         string str=path[i][j];
 78                         str+=char(k+'a');
 79                         if(str<path[i+1][u]) path[i+1][u]=str;
 80                     }
 81                 }
 82             }
 83         }
 84         int ans=0,length=-1;
 85         for(int i=0;i<=n;i++){
 86             for(int j=0;j<tot;j++){
 87                 if(dp[i][j]>ans){
 88                     ans=dp[i][j];
 89                     length=i;
 90                 }
 91             }
 92         }
 93         if(ans==0){
 94             printf("\n");
 95             return;
 96         }
 97         string str="";
 98         for(int j=0;j<tot;j++){
 99             if(dp[length][j]==ans&&(str>path[length][j]||str=="")) str=path[length][j];
100         }
101         printf("%s\n",str.c_str());
102         //printf("%d\n",ans);
103     }
104     
105 };
106 
107 Trie ac;
108 char buf[101][15];
109 int main(){
110     int T;
111     scanf("%d",&T);
112     while(T--){
113         ac.init();
114         scanf("%d%d",&n,&m);
115         for(int i=1;i<=m;i++){
116             scanf("%s",buf[i]);
117         }
118         for(int i=1;i<=m;i++) scanf("%d",val+i),ac.insert(buf[i],val[i]);
119         ac.build();
120         ac.solve(n);
121     }
122 }

 

posted @ 2017-09-13 21:49  Elpsywk  阅读(185)  评论(0编辑  收藏  举报