CF667DIV3-F:dp

传送门:https://codeforces.com/contest/1409/problem/F

比较妙的dp状态定义.

题目大意:

给你一个长度为n的字符串 S S S,给一个长度为2的字符串 T T T,你能更改 S S S不超过 k k k次,让字符串 T T T S S S中出现尽量多。问最多的次数。

n , k ≤ 200 n,k \leq 200 n,k200

题目思路:

本质就是让你构造出一个字符串使得含 T T T的子序列最多

并且T只含有两个.那么考虑一种计数方法:

对于每个T[1]出现的位置,统计前缀中的T[0]的个数,将其累加,就是一个字符串的答案。那么不妨将这个过程转换成dp.

d p ( i , j , k ) dp(i,j,k) dp(i,j,k)代表处理到第 i i i个位置且修改了 j j j个位置。并且前缀中含有 k k k T [ 0 ] T[0] T[0]的最多出现次数。然后转移即可。注意T[0] = T[1]的情况,稍微有点麻烦.具体看代码

注意:将T[0]个数放入dp的状态中的目的就是为了能够统计答案。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 205 + 5;
const int mod = 1e9 + 7;
ll dp[maxn][maxn][maxn];
// dp[i][j][k]代表前i个数,修改了j个数前缀中含有多少个b[0]
ll e[maxn] , w[maxn];
int main()
{
    ios::sync_with_stdio(false);
    ll n , t; cin >> n >> t;
    string a; cin >> a; a = '#' + a;
    string b; cin >> b; b = '#' + b;
    for (int i = 1 ; i <= n ; i++){
        e[i] = (a[i] == b[1]);
        w[i] = (a[i] == b[2]);
    }
    memset(dp , -1 , sizeof dp);
    dp[0][0][0] = 0;
    for (int i = 1 ; i <= n ; i++){
        for (int j = 0 ; j <= t ; j++){
            for (int k = 0 ; k <= i ; k++){
                // 不改
                if (dp[i - 1][j][k - e[i]] != -1 && k - e[i] >= 0)
                    dp[i][j][k] = dp[i - 1][j][k - e[i]] + (k - (b[1] == b[2])) * w[i];
                // 改成 b[1]
                if (dp[i - 1][j - 1][k - 1] != -1 && j && k)
                    dp[i][j][k] = max (dp[i][j][k] , dp[i - 1][j - 1][k - 1] + (b[1] == b[2] ? (k - 1) : 0));
                // 改成b[2]
                if (dp[i - 1][j - 1][k - (b [1] == b[2])] != -1 && j && k - (b[1] == b[2]) >= 0)
                    dp[i][j][k] = max (dp[i][j][k] , dp[i - 1][j - 1][k - (b[1] == b[2])] + k - (b[1] == b[2]));
            }
        }
    }
    ll ans = 0;
    for (int i = 0 ; i <= t ; i++)
        for (int j = 0 ; j <= n ; j++)
            ans = max (ans , dp[n][i][j]);
    cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值