【CF696D】Legen...(AC自动机)(矩阵快速幂)

题目描述
Barney was hanging out with Nora for a while and now he thinks he may have feelings for her. Barney wants to send her a cheesy text message and wants to make her as happy as possible.

Initially, happiness level of Nora is 0 0 . Nora loves some pickup lines like "I'm falling for you" and stuff. Totally, she knows n n pickup lines, each consisting only of lowercase English letters, also some of them may be equal (in writing, but different in pronouncing or meaning though). Every time Nora sees i i -th pickup line as a consecutive subsequence of Barney's text message her happiness level increases by a_{i} a
i
​ . These substrings may overlap, for example, Nora will see the pickup line aa twice and the pickup line ab once in text message aaab.

Due to texting app limits, Barney's text may have up to l l characters.

Barney asked you to help him make Nora as much happy as possible, it's gonna be legen...

Barney与Nora一起玩的时候,觉得自己喜欢上Nora了。他想给她发一段信息让她开心。

Nora的初始快乐值是0 。Nora喜欢“我深深地爱上你了”这样的情话。她一共知道n句情话,每句仅包含小写英文字母,其中的一些可能相同(写法相同,但读音或意思是不同的)。每次Nora在Barney的信息中看到第i句情话,她的快乐值就会增加a_ia
i
​ 。这些情话在信息中可能重叠。例如,在aaab 中,Nora会看到aa 两次,看到ab 一次。

因为短信的长度限制,Barney的短信最长含有lll 个字符。Barney想让你帮他让Nora尽可能开心。

输入输出样例
输入 #1

3 6
3 2 1
heart
earth
art

输出 #1
6
输入 #2

3 6
3 2 8
heart
earth
art

输出 #2
16

这道题可以先把fail树建出来,应为权值是可以重叠的,所以在建fail树的同时也要更新val。

然后可以考虑DP。

(dp[i][j]表示从fail树上点i到点j所可以带来的贡献)

显然可以求得(dp[i][j]),但是N过大,所以我们考虑用矩阵快速幂加速DP。

然后求从根节点到每个节点的贡献,取最大值即可。

#include<bits/stdc++.h>
#define M 210
using namespace std;
struct data
{
	long long ans[M][M];
}ans1;
int tree[M][26],cnt,val[M],sum[M*26],fail[M*26],m;
long long n,maxn;
char s[M];
queue<int> q;
void work()
{
	for(int i=0;i<=cnt;i++)
	{
		for(int j=0;j<=25;j++)
		{
			ans1.ans[i][tree[i][j]]=sum[tree[i][j]];
		}
	}
}
data operator *(data a,data b)
{
	data c;
	memset(c.ans,-1,sizeof(c.ans));
	for(int k=0;k<=cnt;k++)
	{
		for(int i=0;i<=cnt;i++)
		{
			if(a.ans[i][k]!=-1)
			{
				for(int j=0;j<=cnt;j++)
				{
					if(b.ans[k][j]!=-1)
					{
						c.ans[i][j]=max(c.ans[i][j],a.ans[i][k]+b.ans[k][j]);
					}
				}
			}
		}
	}
	return c;
}
void insert(int x)
{
	int rt=0,len=strlen(s);
	for(int i=0;i<len;i++)
	{
		if(!tree[rt][s[i]-'a'])
		{
			tree[rt][s[i]-'a']=++cnt;
		}
		rt=tree[rt][s[i]-'a'];
	}
	sum[rt]+=val[x];
}
void getfail()
{
	for(int i=0;i<=25;i++)
	{
		if(tree[0][i])
		{
			q.push(tree[0][i]);
		}
	}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=0;i<=25;i++)
		{
			int &v=tree[u][i];
			if(!v)
			{
				v=tree[fail[u]][i];
				continue;
			}
			fail[v]=tree[fail[u]][i];
			sum[v]+=sum[fail[v]];
			q.push(v);
	    }
	}
}
data fastpow(data a,int b)
{
	data sum=a;
	while(b)
	{
		if(b&1)
		{
			sum=sum*a;
		}
		b>>=1;
		a=a*a;
	}
	return sum;
}
signed main()
{
	memset(ans1.ans,-1,sizeof(ans1.ans));
	scanf("%lld%lld",&m,&n);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld",&val[i]);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%s",s);
		insert(i);
	}
	getfail();
	work();
	ans1=fastpow(ans1,n-1);
	for(int i=0;i<=cnt;i++)
	{
		maxn=max(maxn,ans1.ans[0][i]);
	}
	printf("%lld
",maxn);
	return 0;
}
原文地址:https://www.cnblogs.com/2017gdgzoi44/p/11780500.html