Codeforces 696 D. Legen...

Description

每个字符串有些价值,问生成长度为 \(l\) 的字符串最多能获得多少价值,总字符数不超过 \(200\), \(l\leqslant 10^{14}\) .

Sol

AC自动机 + 倍增Floyd.

用AC自动机统计到达每个节点会获得的权值.

然后在AC自动机从根节点开始找一条最长路,就用Floyd倍增就可以了...

发现自己AC自动机做Fail树的时候写错了,改了好久没改出来,最后发现不能直接将根扔进队列里...应该把根的所有子节点扔进去..

然后类似快速幂做就可以了.写矩阵的时候需要判断一下能否到达,我用 \(-1\) 来表示能否到达.

转移就是 \(C[i][j]=max\{C[i][j],A[i][k]+B[k][j]\},A[i][k]!=-1,B[k][j]!=-1\) .

Code

#include <bits/stdc++.h>
using namespace std;

const int M = 205;
const int N = 20050;
typedef long long LL;
typedef vector< LL > Vec;
typedef vector< Vec > Mat;

void F(Mat &A,int v=-1) {
	int n=A.size();
	for(int i=0;i<n;i++) for(int j=0;j<n;j++) A[i][j]=v;
}
Mat operator * (const Mat &A,const Mat &B) {
	int n=A.size();Mat C(n,Vec(n));F(C);
	for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++)
		if(A[i][k]!=-1 && B[k][j]!=-1) C[i][j]=max(C[i][j],A[i][k]+B[k][j]);
	return C;
}
Mat operator ^ (Mat A,LL b) {
	int n=A.size();Mat r(n,Vec(n));
	F(r);for(int i=0;i<n;i++) r[i][i]=0;
	for(;b;b>>=1,A=A*A) if(b&1) r=r*A;
	return r;
}
void Print(const Mat &A) {
	int n=A.size();
	for(int i=0;i<n;i++) {
		for(int j=0;j<n;j++) cout<<A[i][j]<<" ";
		cout<<endl;
	}cout<<"---------------------"<<endl;
}

struct AC_Auto {
	int rt,cnt;
	int f[N],ch[N][26],v[N];

	int NewNode() { ++cnt;v[cnt]=f[cnt]=0,memset(ch[cnt],0,sizeof(ch[cnt]));return cnt; }
	void init() { cnt=rt=f[rt]=v[rt]=0;memset(ch[rt],0,sizeof(ch[rt])); }
	void insert(char *s,int val) {
		int l=strlen(s),o=rt;
		for(int i=0;i<l;i++) {
			if(!ch[o][s[i]-‘a‘]) ch[o][s[i]-‘a‘]=NewNode();
			o=ch[o][s[i]-‘a‘];
		}v[o]+=val;
	}
	void getFail() {
		queue< int > q;
		for(int i=0;i<26;i++) if(ch[rt][i]) q.push(ch[rt][i]);
		for(;!q.empty();) {
			int x=q.front();q.pop();
			for(int i=0;i<26;i++) {
				if(!ch[x][i]) ch[x][i]=ch[f[x]][i];
				else q.push(ch[x][i]),f[ch[x][i]]=ch[f[x]][i],v[ch[x][i]]+=v[f[ch[x][i]]];
			}
		}
//		for(int i=0;i<=cnt;i++) cout<<i<<"-->"<<f[i]<<endl;
	}
	void Make(Mat &A) {
		A.resize(cnt+1,Vec(cnt+1));
		int n=A.size();F(A);
		for(int i=0;i<n;i++) for(int j=0;j<26;j++) A[i][ch[i][j]]=v[ch[i][j]],A[i][ch[rt][j]]=v[ch[rt][j]];
	}
}ac;

LL n,l,ans;
LL a[N];
char s[N];

int main() {
//	freopen("in.in","r",stdin);

	ios::sync_with_stdio(false);
	ac.init();

	cin>>n>>l;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>s,ac.insert(s,a[i]);

	ac.getFail();
	Mat r;
	ac.Make(r);

//	Print(r);
	r=r^l;

	for(int i=0;i<(int)r.size();i++) ans=max(ans,r[0][i]);

	cout<<ans<<endl;
	return 0;
}

  

时间: 2024-11-18 23:22:37

Codeforces 696 D. Legen...的相关文章

Codeforces 696 C. PLEASE

Description 三个杯子,一开始钥匙在中间,每次等概率的选择两边的两个,与中间的交换,问第 \(n\) 次选择中间的杯子是钥匙的概率是多少. \(n=\sum_{i=1}^{k} a_i,a_i\leqslant 10^{18}\) Sol 概率DP. 首先 \(a_i\) 表示在中间的概率, \(b_i\) 表示不再中间的概率. 那么 \(a_i=\frac{1}{2}b_{i-1},b_i=1-\frac{1}{2}b_{i-1}\) . 对于 \({b_n}\) 数列,可以解个方程

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

题目大概说给几个字符串,每个字符串都有一个开心值,一个串如果包含一次这些字符串就加上对应的开心值,问长度n的串开心值最多可以是多少. POJ2778..复习下..太弱了都快不会做了.. 这个矩阵的乘法定义是不同的,m[i][j]=max(m1[i][k]+m2[k][j]),即从i走到k能获得的最大值与从k走到j能获得的最大值之和去更新从i到j能获得的最大值. 另外..关于矩阵内的初始值..用-1表示从i不能到j,比如初始的时候,i不能走一步到j结点这时值就应该设置成-1:而不能用0,因为0是有

[Codeforces 696D] Legen...

题目大意: 给出一些匹配串,要造一个长度不超过L的字符串,每个匹配串有自己的价值,匹配串每次出现在字符串里都会贡献一次价值...要求可能得到的最大价值. 匹配串总长不超200,L<=10^14,时限6s 典型的倍增floyd...看数据范围大概就知道是什么东西了= = 暴力写法的话..建个AC自动机,每个节点的价值,就是结束节点在它的fail链上的匹配串的价值总和.. 然后在上面暴力DP.f[i][j]表示从i节点开始,往后走j步能得到的最大价值. 这个形式和USACO那道“奶牛接力跑‘一模一样

【STL】Codeforces 696A Lorenzo Von Matterhorn

题目链接: http://codeforces.com/problemset/problem/696/A 题目大意: 一个满二叉树,深度无限,节点顺序编号,k的儿子是k+k和k+k+1,一开始树上的边权都为0 N(N<=1000)个操作,操作两种,1是从u到v的路径上的所有边权+w,2是求u到v的边权和.(1 ≤ v, u ≤ 1018, v ≠ u, 1 ≤ w ≤ 109) 题目思路: [STL] 用map写很快,第一次用很生疏.现学只看了一点点. 因为是满二叉树所以直接暴力求LCA和求解,

Codeforces Round #362 (Div. 1) B. Puzzles 树形dp,概率

题目链接: http://codeforces.com/problemset/problem/696/B 题意: 一个树,dfs遍历子树的顺序是随机的.所对应的子树的dfs序也会不同.输出每个节点的dfs序的期望 思路: http://www.cnblogs.com/01world/p/5795498.html 假设四个子节点为A,B,C,D,因为排列等可能,所以A在B前面的概率跟A在B后面的概率相等,C和D对于A而言一样.所以遍历A的时间期望就是( t(B) + t(C) + t(D) )/2

【codeforces 696B】 Puzzles

http://codeforces.com/problemset/problem/696/B (题目链接) 题意 给出一棵树,随机dfs遍历这棵树,求解每个节点的期望dfs序. Solution 考虑对于节点u,其某个儿子节点v的期望是多少. 首先,节点u的儿子的dfs的顺序是其儿子数son[x]的全排列.考虑在排列中有多少个节点在v的前面,不妨设x排在v的前面,那么满足的排列数为:${P_n^{n-2}}$,于是x对v的期望的贡献为:$${\frac{P_n^{n-2}×size[x]} {P

【数学相关、规律】Codeforces 696B Puzzles

题目链接: http://codeforces.com/problemset/problem/696/B 题目大意: 给一棵树,从根节点开始递归,time=1,每次递归等概率随机访问这个节点的子节点,走过不会再走,每访问到一个新节点time+1,求访问每个节点的时间的期望. 题目思路: [数学规律] 这题其实是一道概率DP的题目,但是找规律后发现答案和当前结点的子树大小有关. ans[v]=ans[u]+1+0.5*(child[u]-child[v]-1),child为当前节点的子树大小. 1

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b