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 }