BZOJ2121 字符串游戏 【dp】

题目链接

BZOJ2121

题解

dp怎么那么神呐QAQ

我们要求出最小字符串长度
我们设一个\(dp[i]\)表示前\(i\)个字符最后所形成的最短字符串长度
对于第\(i\)个字符,要么保留,就是\(dp[i] = dp[i - 1] + 1\),要么和前面若干个字符一起被删掉

我们设\(c[i][j]\)表示区间\([i,j]\)能否被删掉
如果我们能求出\(c[i][j]\)就好了

我们再设一个\(f[i][j][k][t]\)表示区间\([i,j]\)能否匹配第\(k\)个串的前\(t\)个字符
如果存在一个\(k\),使得\(f[i][j][k][len[k]]\)为真,那么\(c[i][j]\)就为真

所以我们只需考虑如何求出\(f[i][j][k][t]\)
就是简单的区间\(dp\)
枚举断点\(d\),然后\(f[i][j][k][l] |= f[i][d][k][t] \&\& c[d + 1][j]\)

注意转移的顺序,因为\(f\)\(c\)是同时计算的,倒序枚举即可

然后就做完啦

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 155,maxm = 100005,INF = 1000000000;
int f[maxn][maxn][32][23],dp[maxn],c[maxn][maxn],len[32],n,m;
char S[maxn],s[32][23];
int main(){
    scanf("%s",S + 1); m = strlen(S + 1);
    scanf("%d",&n);
    REP(i,n) scanf("%s",s[i] + 1),len[i] = strlen(s[i] + 1);
    for (int i = m; i; i--){
        for (int j = i; j <= m; j++){
            for (int k = 1; k <= n; k++){
                f[i][i - 1][k][0] = 1;
                for (int l = 1; l <= len[k]; l++){
                    f[i][j][k][l] = (f[i][j - 1][k][l - 1] && S[j] == s[k][l]);
                    for (int d = i; d < j; d++)
                        f[i][j][k][l] |= (f[i][d][k][l] && c[d + 1][j]);
                }
            }
            for (int k = 1; k <= n; k++) c[i][j] |= f[i][j][k][len[k]];
        }
    }
    for (int i = 1; i <= m; i++){
        dp[i] = dp[i - 1] + 1;
        for (int j = 1; j <= i; j++) if (c[j][i]) dp[i] = min(dp[i],dp[j - 1]);
    }
    printf("%d\n",dp[m]);
    return 0;
}

转载于:https://www.cnblogs.com/Mychael/p/8993229.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值