codeforces 696D Legen...(AC自动机+矩阵快速幂)

696D Legen...

题意:n个字符串(价值val[i]),请构造长度为l的字符串,使它的价值最大(子串的价值之和)。

题解:

配合 POJ 2778食用。

http://blog.csdn.net/qq_32707623/article/details/54574281


这题要搞清楚End数组的含义(以该节点结束的字符串的价值)。

还要注意矩阵的模型(两状态如果不可达,mat[i][j]=-inf)。

注意单位矩阵的值。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=205;
const ll inf=1e18;
int m;
struct Tire {
	int Next[N][30],fail[N],End[N];
	int root,tot;
	int newNode() {
		memset(Next[tot],-1,sizeof(Next[tot]));
		End[tot]=0;
		return tot++;
	}
	void init() {
		tot=0;
		root=newNode();
	}
	void insert(char *buf,int x) {
		int len=strlen(buf);
		int now=root;
		for(int i=0;i<len;++i) {
			if(Next[now][buf[i]-'a']==-1) {
				Next[now][buf[i]-'a']=newNode(); 
			}
			now=Next[now][buf[i]-'a'];
		}
		End[now]+=x;
	}
	void build() {
		queue<int> q;
		fail[root]=root;
		for(int i=0;i<26;++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 now=q.front();q.pop();
			for(int i=0;i<26;++i) {
				if(Next[now][i]==-1) {
					Next[now][i]=Next[fail[now]][i];
				} else {
					fail[Next[now][i]]=Next[fail[now]][i];
					End[Next[now][i]]+=End[Next[fail[now]][i]];
					q.push(Next[now][i]);
				}
			}
		}
	}
}ac;
struct Mat {
	ll mat[N][N];
	Mat() {
		for(int i=0;i<m;++i) {
			for(int j=0;j<m;++j) {
				mat[i][j]=-inf;
			}
		}
	}
	Mat operator * (Mat B) {
		Mat C;
		for(int i=0;i<m;++i) {
			for(int j=0;j<m;++j) {
				for(int k=0;k<m;++k) {
					C.mat[i][j]=max(C.mat[i][j],mat[i][k]+B.mat[k][j]);
				} 
			}
		}
		return C;
	}
};
Mat powmul(Mat A,ll k) {
    Mat B;
    for(int i=0;i<m;++i) B.mat[i][i]=0;
    while(k) {
        if(k&1) B=B*A;
        A=A*A;
        k>>=1;
    }
    return B;
}
int val[N]; 
char s[N];
int main() {
	int n;ll L;
	while(~scanf("%d%I64d",&n,&L)) {
		ac.init();
		for(int i=1;i<=n;++i) scanf("%d",&val[i]); 
		for(int i=1;i<=n;++i) {
			scanf("%s",s);
			ac.insert(s,val[i]);
		}
		ac.build();
		m=ac.tot;Mat M;
		for(int i=0;i<m;++i) {
			for(int k=0;k<26;++k) {
				int j=ac.Next[i][k];
				M.mat[i][j]=ac.End[j];
			}
		}
		Mat Ans=powmul(M,L);
		ll ans=0;
		for(int i=0;i<m;++i) ans=max(ans,Ans.mat[0][i]);
		printf("%I64d\n",ans);
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值