Codeforces Round #362(Div1) D Legen...(AC自动机+矩阵快速幂)

题目大意:

给定一些开心串,每个串有一个开心值,构造一个串,每包含一次开心串就会获得一个开心值,求最大获得多少开心值。

题解:

首先先建立AC自动机。(建立fail指针的时候,对val要进行累加)

然后在AC自动机上跑dp

dp[i][j] = max(dp[i][j], dp[i-1][k] + v[j])

写成矩阵形式就是(Mat[i][j]表示从i到j最大获得的开心值)

C[i][j] = max(C[i][j], A[i][k]+B[k][j])

然后这个形式也可以用快速幂的形式加速!!

然后救过了!

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N = 205, maxc = 27;
char str[205];
struct Trie{
    int Next[N][maxc], fail[N], tag[N];
    long long val[N];
    int root, L;
    int newnode(){
        for(int i = 0; i < maxc; i++)
            Next[L][i] = -1;
        tag[L++] = 0;
        return L-1;
    }
    void init() { L = 0; root = newnode(); }
    void Insert(char* s, int len, int v){
        int u = root;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            if(Next[u][c] == -1) Next[u][c] = newnode();
            u = Next[u][c];
        }
        tag[u] = 1;
        val[u] += v;
    }
    void build(){
        queue<int> Q;
        fail[root] = root;
        for(int i = 0; i < maxc; i++){
            if(Next[root][i] == -1) Next[root][i] = root;
            else {
                fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        }
        while(!Q.empty()){
            int u = Q.front();
            Q.pop();
            val[u] += val[fail[u]];
            for(int i = 0; i < maxc; i++){
                int &v = Next[u][i];
                if(v == -1){
                    v = Next[fail[u]][i];
                } else {
                    Q.push(v);
                    fail[v] = Next[fail[u]][i];
                }
            }
        }
    }
}ac;

struct Matrix{
    long long Mat[201][201];
    int n;
    Matrix() {n = 0; memset(Mat, 0, sizeof(Mat));}
    Matrix(Matrix &B){
        n = B.n;
        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                Mat[i][j] = B.Mat[i][j];
    }
    Matrix operator +(const Matrix &B)const {
        Matrix C;
        C.n = n;
        for(int i = 0; i <= n; i++)
        for(int j = 0; j <= n; j++){
            C.Mat[i][j] = -1e18;
            for(int k = 0; k <= n; k++)
                C.Mat[i][j] = max(C.Mat[i][j], Mat[i][k] + B.Mat[k][j]);
        }
        return C;
    }
    void print(){
        cout<<"*"<<endl;
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= n; j++) cout<<Mat[i][j]<<" ";
            cout<<endl;
        }
    }
}A;
Matrix mypow(Matrix A, long long b)
{ Matrix ans = A; b--; for(; b; b >>= 1, A = A+A) if(b&1) ans = ans+A; return ans;}
int n, val[205];
long long l;
int main()
{
    ac.init();
    cin>>n>>l;
    for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
    for(int i = 1; i <= n; i++){
        cin>>str;
        ac.Insert(str, strlen(str), val[i]);
    }
    ac.build();
    A.n = ac.L-1;
    for(int i = 0; i < ac.L; i++)
        for(int j = 0; j < ac.L; j++)
            A.Mat[i][j] = -1e18;
    for(int i = 0; i < ac.L; i++){
        for(int j = 0; j < maxc; j++){
            int v = ac.Next[i][j];
            if(v == -1) continue;
            A.Mat[i][v] = ac.val[v];
        }
    }
    A = mypow(A, l);
    long long ans = -1e18;
    for(int i = 0; i < ac.L; i++) ans = max(ans, A.Mat[0][i]);
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Saurus/p/7706626.html