HDU2296 Ring(AC自动机+DP)

题目是给几个带有价值的单词。而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么?

依然是入门的AC自动机+DP题。。不一样的是这题要输出具体方案,加个字符数组记录每个状态最优情况的字符串即可。

另外题目字典序是先考虑长度再考虑每一位单词;特别要注意,有一个非常坑的地方看了Disscus才知道——单词A包含单词B,那么只计算单词A不计算单词B。

  • dp[i][j]表示长度i(自动机上转移k步)后缀状态是自动机第j个结点的字符串的最大价值
  • dp[0][0]=0
  • 我为人人,dp[i][j]向26个字母转移到dp[i'][j']
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 int tn,ch[1111][26],fail[1111],val[1111];
 6 void insert(char *s,int a){
 7     int x=0;
 8     for(int i=0; s[i]; ++i){
 9         int y=s[i]-'a';
10         if(ch[x][y]==0) ch[x][y]=++tn;
11         x=ch[x][y];
12     }
13     val[x]+=a;
14 }
15 void init(){
16     memset(fail,0,sizeof(fail));
17     queue<int> que;
18     for(int i=0; i<26; ++i){
19         if(ch[0][i]) que.push(ch[0][i]);
20     }
21     while(!que.empty()){
22         int x=que.front(); que.pop();
23         for(int i=0; i<26; ++i){
24             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
25             else ch[x][i]=ch[fail[x]][i];
26             //val[ch[x][i]]+=val[ch[fail[x]][i]];
27         }
28     }
29 }
30 char str[111][11];
31 int d[55][1111];
32 char path[55][1111][55]; 
33 int main(){
34     int t,n,m,a;
35     scanf("%d",&t);
36     while(t--){
37         tn=0;
38         memset(ch,0,sizeof(ch));
39         memset(val,0,sizeof(val));
40         scanf("%d%d",&n,&m);
41         for(int i=0; i<m; ++i) scanf("%s",str[i]);
42         for(int i=0; i<m; ++i){
43             scanf("%d",&a);
44             insert(str[i],a);
45         }
46         init();
47         memset(path,0,sizeof(path));
48         memset(d,-1,sizeof(d));
49         d[0][0]=0;
50         for(int i=0; i<n; ++i){
51             for(int j=0; j<=tn; ++j){
52                 if(d[i][j]==-1) continue;
53                 for(int k=0; k<26; ++k){
54                     int &nd=d[i+1][ch[j][k]];
55                     if(nd<d[i][j]+val[ch[j][k]]){
56                         nd=d[i][j]+val[ch[j][k]];
57                         strcpy(path[i+1][ch[j][k]],path[i][j]);
58                         path[i+1][ch[j][k]][i]=k+'a';
59                     }else if(nd==d[i][j]+val[ch[j][k]]){
60                         char tmp[55]={0};
61                         strcpy(tmp,path[i][j]);
62                         tmp[i]=k+'a';
63                         if(strcmp(tmp,path[i+1][ch[j][k]])<0) strcpy(path[i+1][ch[j][k]],tmp);
64                     }
65                 }
66             }
67         }
68         int resi=0,resj=0;
69         for(int i=1; i<=n; ++i){
70             for(int j=0; j<=tn; ++j){
71                 if(d[resi][resj]<d[i][j]) resi=i,resj=j;
72                 else if(d[resi][resj]==d[i][j] && resi==i && strcmp(path[resi][resj],path[i][j])>0) resi=i,resj=j;    
73             }
74         }
75         puts(path[resi][resj]);
76     }
77     return 0;
78 }

 

你可能感兴趣的:(HDU2296 Ring(AC自动机+DP))