[hdu2296]Ring(AC自动机+dp)
2017-09-13 21:49
274 查看
题意:你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]$代表以某前缀的价值总和。
注意这里是多对多的关系,需用从遍历起点时更新后面的点。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cstring> #include<iostream> #include<queue> #include<string> using namespace std; typedef long long ll; const int N=26; const int MAXN=1101; int m,n; int mod=100000; int val[MAXN]; int dp[52][1101]; string path[52][1101]; struct Trie{ int Next[MAXN] ,Fail[MAXN],root,tot; int End[MAXN]; int newnode(){ for(int i=0;i<N;i++) Next[tot][i]=-1; End[tot++]=0; return tot-1; } void init(){ tot=0; root=newnode(); } void insert(char buf[],int x){ int len=(int)strlen(buf),now=root,k; for(int i=0;i<len;i++){ k=buf[i]-'a'; if(Next[now][k]==-1) Next[now][k]=newnode(); now=Next[now][k]; } End[now]=x; } void build(){ queue<int>que; Fail[root]=root; for(int i=0;i<N;i++){ if(Next[root][i]==-1) Next[root][i]=root; else{ Fail[Next[root][i]]=root; que.push(Next[root][i]); } } while(!que.empty()){ int now=que.front(); que.pop(); End[now]+=End[Fail[now]];//此题可重复计算,所以要加 for(int i=0;i<N;i++){ if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; else{ Fail[Next[now][i]]=Next[Fail[now]][i]; que.push(Next[now][i]); } } } } void solve(int n){ memset(dp,-1,sizeof dp); dp[0][0]=0; for(int i=0;i<n;i++){ for(int j=0;j<tot;j++){ if(dp[i][j]==-1) continue; for(int k=0;k<26;k++){ int u=Next[j][k]; if(dp[i][j]+End[u]>dp[i+1][u]){ dp[i+1][u]=dp[i][j]+End[u]; path[i+1][u]=path[i][j]+char(k+'a'); }else if(dp[i][j]+End[u]==dp[i+1][u]){ string str=path[i][j]; str+=char(k+'a'); if(str<path[i+1][u]) path[i+1][u]=str; } } } } int ans=0,length=-1; for(int i=0;i<=n;i++){ for(int j=0;j<tot;j++){ if(dp[i][j]>ans){ ans=dp[i][j]; length=i; } } } if(ans==0){ printf("\n"); return; } string str=""; for(int j=0;j<tot;j++){ if(dp[length][j]==ans&&(str>path[length][j]||str=="")) str=path[length][j]; } printf("%s\n",str.c_str()); //printf("%d\n",ans); } }; Trie ac; char buf[101][15]; int main(){ int T; scanf("%d",&T); while(T--){ ac.init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%s",buf[i]); } for(int i=1;i<=m;i++) scanf("%d",val+i),ac.insert(buf[i],val[i]); ac.build(); ac.solve(n); } }
相关文章推荐
- HDU2296 Ring(AC自动机+DP)
- hdu2296 Ring (AC自动机+dp)
- HDU 2296 Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- hdu 2296 Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- hdu_2296_Ring(AC自动机+DP)
- HDU2296(AC自动机+DP)
- HDU 2296 Ring (AC自动机+DP)
- HDU 2296 Ring(AC自动机+dp)
- HDU 2296 Ring (AC自动机+DP)
- hdu 2296 Ring(AC自动机+DP)
- HDU-2296 Ring(AC自动机+DP)
- hdu2296-(AC自动机+DP)
- hdu2296---Ring(AC自动机+dp)
- hdu 2296 Ring (ac自动机+dp)
- HDU 2296-Ring(AC自动机+DP)
- HDU2296——Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- hdu2296(AC自动机+DP)