题意:
给出m个串,现在要得到长度<=n的串,这个串是有多个串组合而成,串之间可以重叠,每个串对应一个价值。现在要输出总价值最高的串,优先选择短的,字典序小的。
题解:
ac自动机上dp,dp[i][j] 长度为i结尾点为j的最大价值。path[i][j][1110]记录字符串。转移方程要好好理解,很神奇。具体看代码。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef long long ll; const int oo=0x3f3f3f3f; const ll OO=1LL<<61; const ll MOD=20090717; const int maxn=1005; const int SIZE=1005; char str[maxn]; int val[maxn]; int dp[55][SIZE]; char path[55][SIZE][55]; struct AC { int next[SIZE][26],fail[SIZE],end[SIZE],Q[SIZE*26]; int root,cnt; void Init() { cnt=0; root=newNode(); } int newNode() { for(int i=0;i<26;i++) next[cnt][i]=-1; end[cnt++]=-1; return cnt-1; } void Insert(char buff[],int id) { int now=root; int len=strlen(buff); for(int i=0,k;i<len;i++) { k=buff[i]-'a'; if(next[now][k]==-1) next[now][k]=newNode(); now=next[now][k]; } end[now]=id; } void build() { fail[root]=root; int front,rear; front=rear=0; int now=root; for(int i=0;i<26;i++) { if(next[now][i]==-1) next[now][i]=root; else { fail[next[now][i]]=root; Q[rear++]=next[now][i]; } } while(front<rear) { now=Q[front++]; for(int i=0;i<26;i++) { if(next[now][i]==-1) next[now][i]=next[fail[now]][i]; else { fail[next[now][i]]=next[fail[now]][i]; Q[rear++]=next[now][i]; } } } } bool cmp(char s1[],char s2[]) { int len1=strlen(s1); int len2=strlen(s2); if(len1!=len2) return len1<len2; return strcmp(s1,s2)<0; } void DP(int n,int m) { int mx=0; char ans[55]; strcpy(ans,""); memset(dp,-0x3f,sizeof dp); memset(path,0,sizeof path); dp[0][0]=0; strcpy(path[0][0],""); for(int i=0;i<n;i++) { for(int j=0;j<cnt;j++) if(dp[i][j]>=0) { char temp[55]; strcpy(temp,path[i][j]); int len=strlen(temp); for(int t=0;t<26;t++) { int k=next[j][t]; temp[len]='a'+t; temp[len+1]='\0'; int value=0; if(end[k]!=-1) value=val[end[k]]; if(dp[i+1][k]<dp[i][j]+value||(dp[i+1][k]==dp[i][j]+value&&cmp(temp,path[i+1][k]))) { dp[i+1][k]=dp[i][j]+value; strcpy(path[i+1][k],temp); if(dp[i+1][k]>mx||(dp[i+1][k]==mx&&cmp(temp,ans))) { mx=dp[i+1][k]; strcpy(ans,temp); } } } } } printf("%s\n",ans); } }; AC ac; int main() { int n,m,T; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); ac.Init(); for(int i=1;i<=m;i++) { scanf("%s",str); ac.Insert(str,i); } for(int i=1;i<=m;i++) scanf("%d",&val[i]);//cout<<"^_^"<<endl; ac.build(); ac.DP(n,m); } return 0; } /** 10 2 2 hello world 4 1 1 icpc 10 0 0 0 0 0 */