[USACO12JAN]Video Game Combos
贝西在玩一款游戏,该游戏只有三个技能键 “A”“B”“C”可用,但这些键可用形成N种(1 <= N<= 20)特定的组合技。第i个组合技用一个长度为1到15的字符串S_i表示。
当贝西输入的一个字符序列和一个组合技匹配的时候,他将获得1分。特殊的,他输入的一个字符序列有可能同时和若干个组合技匹配,比如N=3时,3种组合技分别为"ABA", “CB”, 和"ABACB",若贝西输入"ABACB",他将获得3分。
若贝西输入恰好K (1 <= K <= 1,000)个字符,他最多能获得多少分?
输入
Line 1: Two space-separated integers: N and K.
Lines 2…N+1: Line i+1 contains only the string S_i, representing combo i.
输出
Line 1: A single integer, the maximum number of points Bessie can obtain.
样例输入
3 7
ABA
CB
ABACB
样例输出
4
提示
The optimal sequence of buttons in this case is ABACBCB, which gives 4 points–1 from ABA, 1 from ABACB, and 2 from CB.
多字符串匹配,先搞出ac自动机,然后我们设dp[i][j],为当前匹配到第i个数,
上一次在ac自动机的第j位,很显然得出方程f[i+1][j”]=max(f[i+1][j”],f[i][j]+当前这一位取某个ABC的贡献);
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
int n,k,cnt,m;
int son[400][3],fail[400],sum[400],dp[1010][400],q[2000];
char s[30];
void insert()
{
int p=0;
for (int i=0;s[i];i++)
{
if (!son[p][s[i]-'A'])
son[p][s[i]-'A']=++cnt;
p=son[p][s[i]-'A'];
}
sum[p]++;
}
void getfail()
{
int head=1,tail=0;
for (int i=0;i<3;i++)
{
if (!son[0][i])
son[0][i]=++cnt;
q[++tail]=son[0][i];
}
while (head<=tail)
{
int now=q[head++];
for (int i=0;i<3;i++)
if (son[now][i])
{
q[++tail]=son[now][i];
fail[son[now][i]]=son[fail[now]][i];
sum[son[now][i]]+=sum[son[fail[now]][i]];
}
else son[now][i]=son[fail[now]][i];
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
insert();
}
getfail();
memset(dp,-2,sizeof dp);
dp[0][0]=0;
for (int i=1;i<=m;i++)
for (int j=0;j<=cnt;j++)
for (int k=0;k<3;k++)
dp[i][son[j][k]]=max(dp[i][son[j][k]],dp[i-1][j]+sum[son[j][k]]);
int ans=0;
for (int i=0;i<=cnt;i++)
ans=max(ans,dp[m][i]);
printf("%d",ans);
return 0;
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define N 1005
std::queue<int>q;
int t[N][3],fail[N],val[N],vis[N][N],dp[N][N];
char c[N];
int n,m,cnt,ans;
void ins(){
int len=strlen(c),now=0;
for (int i=0;i<len;i++)
{
int u=c[i]-'A';
if (t[now][u])
now=t[now][u];
else
now=t[now][u]=++cnt;
}
val[now]++;
}
void getfail()
{
for (int i=0;i<3;i++)
if (t[0][i]) q.push(t[0][i]);
fail[0]=0;
while (!q.empty())
{
int u=q.front();
q.pop();
for (int i=0;i<3;i++)
{
int v=t[u][i];
if (v)
fail[v]=t[fail[u]][i],q.push(v);
else
t[u][i]=t[fail[u]][i];
}
}
}
int solve(int x,int y)
{
while (x)
y+=val[x],x=fail[x];
return y;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%s",c);
ins();
}
getfail();
vis[0][0]=1;
for (int i=0;i<m;i++)
{
for (int j=0;j<=cnt;j++)
{
if (vis[i][j]==0)
continue;
for (int k=0;k<3;k++)
{
int tmp=t[j][k];
//上一次走到了[i,j],现在从j这个点走到其子结点k
dp[i+1][tmp]=std::max(dp[i+1][tmp],solve(tmp,dp[i][j]));
vis[i+1][tmp]=1;
}
}
}
for (int i=0;i<=cnt;i++) ans=std::max(ans,dp[m][i]);
printf("%d",ans);
}

浙公网安备 33010602011771号