HDU2296 Ring(AC自动机 DP)

dp[i][j]表示行走i步到达j的最大值,dps[i][j]表示对应的串

 

状态转移方程如下:

dp[i][chi[j][k]] = min(dp[i - 1][j] + sum[chi[j][k]])

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;

#define hash(x) x-'a';
const int N = 20000, CH = 26, INF = 0x3F3F3F3F;
int n, m;
struct Trie{
    Trie *next[CH];
    Trie *fail;
    int id;
}tree[N];
string dps[60][2008];
string ans;

//dp[i][j]表示行走i步到达j的最大值,dps[i][j]表示对应的串
int dp[60][2008];
int chi[1008][CH];
int sum[1008];

//先选长度短的,再按字典序选
inline string min(string &a, string &b){
    if(a.size() != b.size()){
        return a.size() < b.size()? a :b;
    }
    return a < b? a :b;
}
class AC_Auto{
        int size;
        Trie *root;
        int mx;

    public:
    AC_Auto(){
        root = &tree[0];
        size=0;
        memset(&tree[0], 0, sizeof(Trie));
    }

    void insert(char *s, int si){
        Trie *p = root;
        for(int i = 0; s[i]; i++){
            int c = hash(s[i]);
            if(!p -> next[c]){
                memset(&tree[++size], 0, sizeof(Trie));
                p -> next[c] = &tree[size];
                p -> next[c] ->id = size;
            }
            p = p -> next[c];
        }
        sum[p -> id] = si;
    }

    void build(){
        queue<Trie *> q;
        q.push(root);
        root -> fail = NULL;
        while(!q.empty()){
            Trie *now = q.front();
            q.pop();
            if(now -> fail){
                //累加求串包含的子串价值和
                sum[now -> id] += sum[now -> fail -> id];
            }
            for(int i = 0; i < CH; i++){
                Trie *son = now -> next[i];
                Trie *tp = (now == root)? root: now -> fail->next[i];
                if(son == NULL){
                    now -> next[i] = tp;
                }else{
                    son -> fail = tp;
                    q.push(son);
                }
                son = now -> next[i];
                chi[now -> id][i] = son->id;
            }
        }
    }
    void solve(){
        mx = 0;
        ans.clear();
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= size; j++){
                dp[i][j] = -INF;
                dps[i][j].clear();
            }
        }
        dp[0][0] = 0;
        //枚举步骤,再枚举节点,状态转移
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= size; j++){
                if(dp[i - 1][j] < 0){
                    continue;
                }
                for(int k = 0; k < CH; k++){
                    if(dp[i][chi[j][k]] < dp[i - 1][j] + sum[chi[j][k]]){
                        dp[i][chi[j][k]] = dp[i - 1][j] + sum[chi[j][k]];

                        dps[i][chi[j][k]] = dps[i - 1][j] + (char)(k + 'a');

                    }else if(dp[i][chi[j][k]] == dp[i - 1][j] + sum[chi[j][k]]){
                        dps[i][chi[j][k]] = min(dps[i - 1][j] + (char)(k + 'a'), dps[i][chi[j][k]]);
                    }

                    if(mx < dp[i][chi[j][k]]){
                        mx = dp[i][chi[j][k]];
                        ans = dps[i][chi[j][k]];
                    }else if(mx == dp[i][chi[j][k]]){
                        ans = min(ans, dps[i][chi[j][k]]);
                    }
                }
            }

        }
        if(ans.size() > 0){
            cout<<ans<<"\n";
        }else{

            cout<<"\n";
        }

    }
};

char str[1008][1008];
int main(){
    int t;
    cin>>t;
    while(t--){
        AC_Auto ac;
        cin>>n>>m;
        memset(sum, 0 ,  sizeof(sum));

        for(int i = 0; i < m; i++){
            scanf("%s", str[i]);
        }
        for(int i = 0; i < m ; i++){
            int val;
            scanf("%d", &val);
            ac.insert(str[i], val);
        }
        ac.build();
        ac.solve();
    }
    return 0;
}

  

posted @ 2016-08-27 16:44  vwirtveurit  阅读(309)  评论(0编辑  收藏  举报