P3041 [USACO12JAN]视频游戏的连击Video Game Combos

P3041 [USACO12JAN]视频游戏的连击Video Game Combos

看到匹配,当然用AC自动机

常我们有文本串,这里仅给出长度,怎么计算得分呢

按模式串建自动机,跑一边(dp),字符集较小,都不需要统计每个点的值

直接往上扫累加就行

**My complete code: **

#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn=1100;
inline LL Read(){
    LL x=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<3)+(x<<1)+c-'0'; c=getchar();
    }return x*f;
}
LL n,K,ans,nod;
LL son[maxn][5],val[maxn],fail[maxn],dp[maxn][maxn];
bool visit[maxn][maxn];
char s[maxn];
inline void Build(char *s){
    LL len=strlen(s),u=0;
    for(LL i=0;i<len;++i){
        LL c=s[i]-'A';
        if(!son[u][c])
            son[u][c]=++nod;
        u=son[u][c];
    }
    ++val[u];
}
inline void Bfail(){
    queue<LL> que;
    for(LL i=0;i<3;++i)
        if(son[0][i])
            que.push(son[0][i]);
    while(que.size()){
        LL u=que.front(); que.pop();
        for(LL i=0;i<3;++i){
            LL v=son[u][i];
            if(v){
            	fail[v]=son[fail[u]][i];
            	que.push(v);
            }else
                son[u][i]=son[fail[u]][i];
        }
    }
}
inline LL Get(LL v,LL sum){
    while(v)
        sum+=val[v],
        v=fail[v];
    return sum;
}
int main(){
    n=Read(),K=Read();
    for(LL i=1;i<=n;++i){
        scanf(" %s",s);
        Build(s);
    }
    Bfail();
    visit[0][0]=true;
    for(LL i=0;i<K;++i){
        for(LL j=0;j<=nod;++j){
            if(!visit[i][j])
                continue;
            for(LL k=0;k<3;++k){
                LL v=son[j][k];
                dp[i+1][v]=max(dp[i+1][v],Get(v,dp[i][j]));
                visit[i+1][v]=true;
            }
        }
    }
    for(LL i=1;i<=nod;++i)
        ans=max(ans,dp[K][i]);
    printf("%lld",ans);
    return 0;
}/*
3 7 
ABA 
CB 
ABACB 

4
*/
原文地址:https://www.cnblogs.com/y2823774827y/p/10153636.html