P3041 [USACO12JAN]Video Game G
P3041 [USACO12JAN]Video Game G
完全不知道为什么数据范围这么小,而且我一遍写完就AC了。。。
考虑如果我们知道了 \(Bessie\) 输入的字符串,那么答案就是:把所有模式串建 \(ACAM\) ,让文本串沿着 \(Trie\) 图跑,所有经过的节点打标记,统计每个模式串终止节点子树内的标记个数和。
可是这个字符串是自己构造的。。。
我们发现我们可以知道走到 \(Trie\) 图上面的每一个节点产生的贡献:即从它到根的路径上有几个模式串的终止节点,因为一旦走到这个点,那些终止节点的子树和都会加一。
所以现在的问题是:你的面前有一张图,点数不超过 \(300\) ,有点权,求长度为 \(k(k\le 1000)\) 的路径中经过点的点权和最大是多少
设\(dp[i][j]\) 表示在 \(i\) 这个节点还可以(或者已经走)走 \(j\) 步的方案数,直接 \(dp\) 或者记搜就能过了。
复杂度 \(O(\sum |S|\cdot k)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define x first
#define y second
#define sz(v) (int)v.size()
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
while(isdigit(c))x=x*10+c-'0',c=getchar();
return f?x:-x;
}
int n,k,ch[305][3],tot,cnt[305],dp[305][1005],fail[305];
vector<int>e[305];
void insert(char*str){
int u=0,len=strlen(str);
for(int i=0;i<len;++i){
int c=str[i]-'A';
if(!ch[u][c])ch[u][c]=++tot;
u=ch[u][c];
}
++cnt[u];
}
void build_fail(){
queue<int>q;
for(int i=0;i<3;++i)if(ch[0][i])q.push(ch[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<3;++i)
if(ch[u][i])fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]);
else ch[u][i]=ch[fail[u]][i];
}
for(int i=1;i<=tot;++i)e[fail[i]].pb(i);
}
void dfs1(int u){
for(int v:e[u])cnt[v]+=cnt[u],dfs1(v);
}
int dfs2(int u,int k){
if(~dp[u][k])return dp[u][k];
if(!k)return cnt[u];
int res=0;
for(int i=0;i<3;++i)res=max(res,dfs2(ch[u][i],k-1));
return dp[u][k]=res+cnt[u];
}
signed main(){
n=read(),k=read();
for(int i=1;i<=n;++i){
static char str[20];
scanf("%s",str),insert(str);
}
build_fail(),dfs1(0);
memset(dp,-1,sizeof(dp));
printf("%d\n",dfs2(0,k));
}
路漫漫其修远兮,吾将上下而求索