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