贝西在玩一款游戏,该游戏只有三个技能键 “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); }