LGP3041 Video Game G (AC自动机+dp)

LGP3041 Video Game G

Mean

Bessie 在玩一款游戏,该游戏只有三个技能键 A,B,C 可用,但这些键可用形成 \(n\) 种特定的组合技。第 \(i\) 个组合技用一个字符串 \(s_i\)表示。
Bessie 会输入一个长度为 \(k\) 的字符串 \(t\),而一个组合技每在 \(t\) 中出现一次,Bessie 就会获得一分。\(s_i\)在 tt 中出现一次指的是 \(s_i\)\(t\) 从某个位置起的连续子串。如果 \(s_i\)\(t\) 的多个位置起都是连续子串,那么算作 \(s_i\)出现了多次。
若 Bessie 输入了恰好 \(k\) 个字符,则她最多能获得多少分?

Sol

AC自动机+dp

定义一个节点的权值\(cnt[x]\),代表\(x\)节点向上跳\(fail\)时一共能经过多少个终止节点.
定义一条路径的权值为该路径上所有点权的和.

问题转换成在状态机上走\(m\)步,所有长度为\(m\)的路径中,路径权值的最大值.

\(dp[i][j]\),代表当前走了\(i\)步,走到状态机上节点\(j\)时,长度为\(i\)的最大路径值.

则有 \(dp[i+1][tr[j][op]]=max(dp[i+1][tr[j][op]],dp[i][j]+(cnt[tr[j][op]]));\)

最后统计一下最大值即可.

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
inline ll read() {
    char c=getchar();ll x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
    return x*f;
}

inline void out(int x) {   
  if(x>9) out(x/10);   
  putchar(x%10+'0'); 
}     
const int mod = 1e4+7;
const int N = 10000+10;
const int M = 200;
int tr[N][4],fail[N];
int vis[N];
/**
 * AC自动机 + dp
 * 求长度为m的任意串 中匹配串出现的最多次数
 */
char s[N];
int tot;
int n,k;
int dp[1005][500];
int cnt[N];
int qpow(int a,int b){
  int ans=1;
  while(b){
    if(b&1){
      ans=(1ll*ans*a)%mod;
    }
    a=(1ll*a*a)%mod;
    b>>=1;
  }
  return ans;
}
void insert(int id){
  int p=0;
  for(int i=1;s[i];i++){
    int v=s[i]-'A';
    if(!tr[p][v]){
      tr[p][v]=++tot;
    }
    p=tr[p][v];
  }
  vis[p]=1;
  cnt[p]=1;
}
void build(){
  queue<int>Q;
  for(int i=0;i<3;++i){
    if(tr[0][i]){
      Q.push(tr[0][i]);
    }
  }
  while(!Q.empty()){
    int p = Q.front();
    Q.pop();
    for(int i=0;i<3;++i){
      if(tr[p][i]){
        fail[tr[p][i]]=tr[fail[p]][i];  
        Q.push(tr[p][i]);
        cnt[tr[p][i]]+=cnt[fail[tr[p][i]]];
      }
      else{
        tr[p][i]=tr[fail[p]][i];
      }
    }
  }
}
int main(){
  scanf("%d %d",&n,&k);
  for(int i=1;i<=n;++i){
    scanf("%s",s+1);
    insert(i);
  }
  build();
  for(int i=0;i<=k;++i){
    for(int j=0;j<=tot;++j){
      dp[i][j]=-0x3f3f3f3f;
    }
  }
  dp[0][0]=0;
  for(int i=0;i<k;++i){
    for(int j=0;j<=tot;++j){
      for(int op=0;op<3;++op){
        dp[i+1][tr[j][op]]=max(dp[i+1][tr[j][op]],dp[i][j]+(cnt[tr[j][op]]));
      }
    }
  }
  int ans=0;
  for(int i=0;i<=tot;++i){
    ans=max(ans,dp[k][i]);
  }
  printf("%d\n",ans);

}
posted @ 2021-10-18 16:50  Qquun  阅读(54)  评论(0)    收藏  举报