chino with string(2021 XJCPC A)
题目大意
给你\(m\)个串,每个串都有各自的价值,现在让你构造出一个长度为\(n\)的新串,新串的价值为所有出现在其中的串的价值乘上出现次数的总和,问新串价值最大为多少。\((1\leq n\leq10^9,1\leq m\leq200,-10^6\leq v\leq10^6,\sum|s|\leq200)\)
思路
首先肯定会想到\(DP\),但是由于数据范围很大,肯定不能暴力用\(DP\)来做
,所以就下班了,但是我们又发现串的长度只有\(200\),那就可以用矩阵快速幂来优化\(DP\)了。但是这个矩阵不同于传统的矩阵,这里矩阵乘法是用内层加法,外层取\(max\)来实现的,然后初值全赋为\(-0x3f3f3f3f\),最后的\(ans\)初值得赋成\(-1e18\)!!!然后就\(AC\)了。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=205;
const int inf=0x3f3f3f3f;
int trie[MAXN][26];
int ed[MAXN];
int fail[MAXN];
int tot=0;
void insert(char* s,int val)
{
int len=strlen(s),p=0;
for(int i=0;i<len;i++)
{
int ch=s[i]-'a';
if(trie[p][ch]==0)trie[p][ch]=++tot;
p=trie[p][ch];
}
ed[p]+=val;
}
void build()
{
queue<int>q;
memset(fail,0,sizeof(fail));
for(int i=0;i<26;i++)if(trie[0][i])q.push(trie[0][i]);
while(!q.empty())
{
int fa=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(trie[fa][i])
{
fail[trie[fa][i]]=trie[fail[fa]][i];
q.push(trie[fa][i]);
}
else trie[fa][i]=trie[fail[fa]][i];
}
ed[fa]+=ed[fail[fa]];
}
}
struct Matrix
{
long long mat[205][205];
Matrix(){memset(mat,-inf,sizeof(mat));}
Matrix operator*(const Matrix& a)const
{
Matrix ans;
for(int i=0;i<=tot;i++)
for(int j=0;j<=tot;j++)
for(int k=0;k<=tot;k++)
{
if(mat[i][k]==-inf||a.mat[k][j]==-inf)continue;
ans.mat[i][j]=max(ans.mat[i][j],mat[i][k]+a.mat[k][j]);
}
return ans;
}
};
Matrix poww(Matrix& a,long long n)
{
Matrix ans=a;
n--;
while(n)
{
if(n&1)ans=ans*a;
a=a*a;
n>>=1;
}
return ans;
}
char s[205];
Matrix M;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
while(m--)
{
int val;
scanf("%s%d",s,&val);
insert(s,val);
}
build();
for(int i=0;i<=tot;i++)
for(int j=0;j<26;j++)
{
M.mat[i][trie[i][j]]=ed[trie[i][j]];
}
M=poww(M,n);
long long ans=-1e18;
for(int i=0;i<=tot;i++)
ans=max(ans,M.mat[0][i]);
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号