您的位置:首页 > 其它

[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);
}
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: