题意
给一组字符串,每个字符串有一个值,如果一个字符串包含这个子串,那么总值就加上这个子串的值。给一个长度,问能组成的最大值。
题解
对于要求长度1000的情况,我们可以直接DP。但是这道题不
行,这道题长度达到了10^16。我们考虑用矩阵快速幂加速。
我们很容易便能得到一个状态转移方程,dp[i][j]=max(dp[i][j],dp[i][k]+dp[k][j])。这个状态转移方程中的I,J,K都是AC自动机中的点。这个看起来像区间DP的状态转移方程其实有着很有趣的特性。我们可以发现这个状态转移4次的值,实际上就是转移两次的矩阵+转移两次的矩阵(这里的加法进行了重新定义,计算方式就是上述那个状态转移方程)。有了这个性质,我们便可以直接利用矩阵快速幂进行计算了。最后的话,取从0开始的最大值就可以了。
注意事项
需要注意进行矩阵快速幂的时候初始化矩阵不能新建一个矩阵,而是要利用计算好的A矩阵。因为如果新建一个矩阵就意味着可以从任意一个点开始,这样的话会造成结果的偏差。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#include<string>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 220
#define MOD 1000000007
#define EPS 1e-3
#define int LL
using namespace std;
int ch[MAXN][26];
int val[MAXN],aval[220],f[MAXN];
char s[220];
int sz;
struct Matrix{
int mt[MAXN][MAXN];
void init(){
MEM(mt,0);
}
Matrix operator + (const Matrix b) const{
Matrix m;
m.init();
UP(i,0,sz){
UP(j,0,sz){
m.mt[i][j]=-INF;
UP(k,0,sz){
m.mt[i][j]=max(m.mt[i][j],mt[i][k]+b.mt[k][j]);
// if(m.mt[i][j]==8) cout<<m.mt[i][j]<<" "<<i<<" "<<j<<" "<<k<<endl;
}
}
}
return m;
}
};
Matrix quick_pow(Matrix a,int n){
Matrix m=a;
n--;
W(n){
if(n&1) m=m+a;
a=a+a;
n>>=1;
}
return m;
}
void insert(int k){
int u=0,n=strlen(s);
UP(i,0,n){
int c=s[i]-'a';
if(!ch[u][c]){
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]+=aval[k];
// cout<<u<<" "<<val[u]<<endl;
}
void getFail(){
queue<int> q;
MEM(f,0);
UP(c,0,26){
if(ch[0][c]){
q.push(ch[0][c]);
}
}
W(!q.empty()){
int r=q.front();
q.pop();
UP(c,0,26){
int u=ch[r][c];
if(!u){ch[r][c]=ch[f[r]][c];continue;}
q.push(u);
int v=f[r];
f[u]=ch[v][c];
val[u]+=val[f[u]];
}
}
}
main(){
MEM(val,0);
MEM(ch,0);
sz=1;
int n,l;
scanf("%I64d%I64d",&n,&l);
UP(i,0,n) scanf("%I64d",&aval[i]);
UP(i,0,n) scanf("%s",s),insert(i);
getFail();
Matrix mt;
UP(i,0,sz) UP(j,0,sz) mt.mt[i][j]=-INF;
UP(i,0,sz){
UP(j,0,26){
if(ch[i][j]) mt.mt[i][ch[i][j]]=val[ch[i][j]];
}
}
Matrix ans=quick_pow(mt,l);
int mx=0;
UP(i,0,sz){
mx=max(mx,ans.mt[0][i]);
// cout<<ans.mt[0][i]<<" "<<i<<endl;
}
printf("%I64d\n",mx);
}