zoukankan      html  css  js  c++  java
  • [hdu2296]Ring(AC自动机+dp)

    题意:你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]$代表以某前缀的价值总和。

    注意这里是多对多的关系,需用从遍历起点时更新后面的点。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<iostream>
      7 #include<queue>
      8 #include<string>
      9 using namespace std;
     10 typedef long long ll;
     11 const int N=26;
     12 const int MAXN=1101;
     13 int m,n;
     14 int mod=100000;
     15 int val[MAXN];
     16 int dp[52][1101];
     17 string path[52][1101];
     18 struct Trie{
     19     int Next[MAXN][N],Fail[MAXN],root,tot;
     20     int End[MAXN];
     21     int newnode(){
     22         for(int i=0;i<N;i++) Next[tot][i]=-1;
     23         End[tot++]=0;
     24         return tot-1;
     25     }
     26     void init(){
     27         tot=0;
     28         root=newnode();
     29     }
     30     
     31     void insert(char buf[],int x){
     32         int len=(int)strlen(buf),now=root,k;
     33         for(int i=0;i<len;i++){
     34             k=buf[i]-'a';
     35             if(Next[now][k]==-1)  Next[now][k]=newnode();
     36             now=Next[now][k];
     37         }
     38         End[now]=x;
     39     }
     40     
     41     void build(){
     42         queue<int>que;
     43         Fail[root]=root;
     44         for(int i=0;i<N;i++){
     45             if(Next[root][i]==-1) Next[root][i]=root;
     46             else{
     47                 Fail[Next[root][i]]=root;
     48                 que.push(Next[root][i]);
     49             }
     50         }
     51         while(!que.empty()){
     52             int now=que.front();
     53             que.pop();
     54                End[now]+=End[Fail[now]];//此题可重复计算,所以要加
     55             for(int i=0;i<N;i++){
     56                 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i];
     57                 else{
     58                     Fail[Next[now][i]]=Next[Fail[now]][i];
     59                     que.push(Next[now][i]);
     60                 }
     61             }
     62         }
     63     }
     64     
     65     void solve(int n){
     66         memset(dp,-1,sizeof dp);
     67         dp[0][0]=0;
     68         for(int i=0;i<n;i++){
     69             for(int j=0;j<tot;j++){
     70                 if(dp[i][j]==-1) continue;
     71                 for(int k=0;k<26;k++){
     72                     int u=Next[j][k];
     73                     if(dp[i][j]+End[u]>dp[i+1][u]){
     74                         dp[i+1][u]=dp[i][j]+End[u];
     75                         path[i+1][u]=path[i][j]+char(k+'a');
     76                     }else if(dp[i][j]+End[u]==dp[i+1][u]){
     77                         string str=path[i][j];
     78                         str+=char(k+'a');
     79                         if(str<path[i+1][u]) path[i+1][u]=str;
     80                     }
     81                 }
     82             }
     83         }
     84         int ans=0,length=-1;
     85         for(int i=0;i<=n;i++){
     86             for(int j=0;j<tot;j++){
     87                 if(dp[i][j]>ans){
     88                     ans=dp[i][j];
     89                     length=i;
     90                 }
     91             }
     92         }
     93         if(ans==0){
     94             printf("
    ");
     95             return;
     96         }
     97         string str="";
     98         for(int j=0;j<tot;j++){
     99             if(dp[length][j]==ans&&(str>path[length][j]||str=="")) str=path[length][j];
    100         }
    101         printf("%s
    ",str.c_str());
    102         //printf("%d
    ",ans);
    103     }
    104     
    105 };
    106 
    107 Trie ac;
    108 char buf[101][15];
    109 int main(){
    110     int T;
    111     scanf("%d",&T);
    112     while(T--){
    113         ac.init();
    114         scanf("%d%d",&n,&m);
    115         for(int i=1;i<=m;i++){
    116             scanf("%s",buf[i]);
    117         }
    118         for(int i=1;i<=m;i++) scanf("%d",val+i),ac.insert(buf[i],val[i]);
    119         ac.build();
    120         ac.solve(n);
    121     }
    122 }
  • 相关阅读:
    (转载)什么才是富人思维
    linux上的vs code的C++环境搭建
    [转载]双线性插值简介
    刻意练习行动手册
    滑动窗口技巧
    [转载]用于深入思考的小工具
    CF632E Thief in a Shop
    BZOJ1497 最大获利
    UVA10779 Collectors Problem
    洛谷P4311 士兵占领
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7517898.html
Copyright © 2011-2022 走看看