[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);
}

  

posted @ 2020-04-01 11:25  我微笑不代表我快乐  阅读(139)  评论(0编辑  收藏  举报