[USACO12JAN][SPOJ10502][Luogu3041]Video Game Combos

传送门
SPOJ10502
Luogu3041

Description

Bessie is playing a video game! In the game, the three letters ‘A’, ‘B’,and ‘C’ are the only valid buttons. Bessie may press the buttons in any order she likes; however, there are only N distinct combos possible (1 <= N<= 20). Combo i is represented as a string S_i which has a length between 1 and 15 and contains only the letters ‘A’, ‘B’, and ‘C’.
Whenever Bessie presses a combination of letters that matches with a combo, she gets one point for the combo. Combos may overlap with each other or even finish at the same time! For example if N = 3 and the three possible combos are “ABA”, “CB”, and “ABACB”, and Bessie presses “ABACB”, she will end with 3 points. Bessie may score points for a single combo more than once.
Bessie of course wants to earn points as quickly as possible. If she presses exactly K buttons (1 <= K <= 1,000), what is the maximum number of points she can earn?
给你个模式串(每个长度≤15,1≤N≤20),串中只含有“ABC”三种字母。求一长度为K(1≤K≤1000)的字符串,使得匹配数最大(重复匹配计多次),输出最大值。

Input

  • 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.

Output

  • Line 1: A single integer, the maximum number of points Bessie can obtain.

Sample Input

3 7
ABA
CB
ABACB

Sample Output

4

Hint

The optimal sequence of buttons in this case is ABACBCB, which gives 4 points–1 from ABA, 1 from ABACB, and 2 from CB.

Solution

  • AC自动机模板+DP
  • val[u]表示后缀树上u及其子孙中危险节点总和。(此处后缀树指fail指针反向构成的树)
  • f[step][u]表示第step步走到u节点的最优答案
  • 需要注意的是如果当前危险节点的模式串长度小于step,答案是不可以更新的,p数组用来判断这个,相当于表示该状态有没有到达过。第一次由于这个WA掉了

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
queue <int>q;
char s[27];
int n,m,sz;
int f[1007][307],ch[307][7],val[307],fail[307];
bool p[1007][307];
void insert(char *s,int id){
    int u=1,n=strlen(s);
    for (int i=0;i<n;i++){
        int c=s[i]-'A';
        if (!ch[u][c]){
            //memset(ch[sz],0,sizeof(ch[sz]));
            //val[sz]=0;
            ch[u][c]=++sz;
        }
        u=ch[u][c];
    }
    val[u]=1;
}
void getFail(){
    int rt=1;
    fail[rt]=1;
    for (int i=0;i<3;i++){
        int u=ch[rt][i];
        fail[u]=rt;
        if (u){fail[u]=rt; q.push(u);}
            else ch[rt][i]=rt;
    }
    while (!q.empty()){
        int u=q.front(); q.pop();
        for (int i=0;i<3;i++){
            int v=ch[u][i];
            if (v){fail[v]=ch[fail[u]][i]; q.push(v);}
                else ch[u][i]=ch[fail[u]][i];
        }
        if (val[fail[u]]) val[u]+=val[fail[u]];
    }
}
int main(){
    scanf("%d%d",&n,&m);
    sz=1;
    for (int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s,i);
    }
    getFail();
    //printf("sz=%d\n",sz);
    p[0][1]=1;
    for (int step=0;step<m;step++)
    for (int u=1;u<=sz;u++)
    if (p[step][u])
    for (int v=0;v<3;v++){
        int i=ch[u][v];
        p[step+1][i]=p[step][u];
        f[step+1][i]=max(f[step+1][i],f[step][u]+val[i]);
    }
    //for (int i=1;i<=sz;i++) printf("%d ",val[i]); printf("\n");
    int ans=0;
    /*
    for (int i=0;i<=7;i++)
    for (int j=1;j<=sz;j++)
        printf("f[%d][%d]=%d\n",i,j,f[i][j]);
    */
    for (int i=1;i<=sz;i++) ans=max(ans,f[m][i]);
    printf("%d",ans);
    return 0;
}
//SP10502
//Luogu 3041 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值