1. 程式人生 > >Codeforces Round #362(Div1) D Legen...(AC自動機+矩陣快速冪)

Codeforces Round #362(Div1) D Legen...(AC自動機+矩陣快速冪)

max pri i++ == strlen ems out tin ces

題目大意:

給定一些開心串,每個串有一個開心值,構造一個串,每包含一次開心串就會獲得一個開心值,求最大獲得多少開心值。

題解:

首先先建立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; }

Codeforces Round #362(Div1) D Legen...(AC自動機+矩陣快速冪)