牛客 - 牛牛的01限定串

题目描述

牛牛的01限定串

解法:DP(C++)

我们先考虑这样一个问题:如果 t t t 串全是 ?

如样例一

8 6 2 1 1
10110011
????????

这时如果我们看做纸条问题,那么也就是:求一条从 ( 0 , 0 ) (0,0) (0,0) ( c n t 0 , c n t 1 ) (cnt0,cnt_1) (cnt0,cnt1)的路径,只能向右(取0)或向下(取1)走,使得路径上的点的权值和最大。

于是,我们就得一个 ( 6 + 1 ) × ( 2 + 1 ) (6+1)\times(2+1) (6+1)×(2+1)的棋盘,左上角记为 ( 0 , 0 ) (0,0) (0,0)
在这里插入图片描述
那么,现在的问题是,从左上角走到右下角有多少种走法?好的,是 C ( 8 , 6 ) C(8,6) C(8,6)种。

那用 6 个 0 和 2 个 1 组成不同的字符串,有多少种?巧了,也是 C ( 8 , 6 ) C(8,6) C(8,6)种。

于是,纸条问题就和这道题对应起来了,这时很容易就想到用动态规划。

d p [ x ] [ y ] dp[x][y] dp[x][y]表示 ( x , y ) (x, y) (x,y)的得分, a [ x ] [ y ] a[x][y] a[x][y]表示到达 ( x , y ) (x, y) (x,y)这一步的得分,那么就有:

d p [ x ] [ y ] = m a x ( d p [ x − 1 ] [ y ] , d p [ x ] [ y − 1 ] ) + a [ x ] [ y ] dp[x][y]=max(dp[x−1][y],dp[x][y−1])+a[x][y] dp[x][y]=max(dp[x1][y],dp[x][y1])+a[x][y]

对应题目,细化一下转移方程, p o s pos pos表示当前在棋盘的位置对应到字符串的位置, s u m [ x ] sum[x] sum[x] 表示标准串 s s s,到第 x x x 位置为止共有多少个 1, 满足 s s s t t t 前缀 x 1 x_1 x1 相同等价于 s u m [ x 1 ] = = j sum[x_1]==j sum[x1]==j,后缀 x 1 + 1 ~ n x_1+1~n x1+1n 相同就等价于 s u m [ n ] − s u m [ x 1 ] = = c n t 1 − j sum[n]-sum[x_1]==cnt_1-j sum[n]sum[x1]==cnt1j

t [ p o s ] = = 0 t[pos]==0 t[pos]==0,即只能右走
m m a x [ i ] [ j ] = m a x ( m m a x [ i ] [ j ] , m m a x [ i ] [ j − 1 ] + v a l p r e ∗ ( s u m [ p o s ] = = j ) + v a l s u f ∗ ( s u m [ n ] − s u m [ p o s ] = = c n t 1 − j ) ) mmax[i][j]=max(mmax[i][j],mmax[i][j-1]+val_{pre}*(sum[pos]==j)+val_{suf}*(sum[n]-sum[pos]==cnt_1-j)) mmax[i][j]=max(mmax[i][j],mmax[i][j1]+valpre(sum[pos]==j)+valsuf(sum[n]sum[pos]==cnt1j))

t [ p o s ] = = 1 t[pos]==1 t[pos]==1,即只能右走
m m a x [ i ] [ j ] = m a x ( m m a x [ i ] [ j ] , m m a x [ i − 1 ] [ j ] + v a l p r e ∗ ( s u m [ p o s ] = = j ) + v a l s u f ∗ ( s u m [ n ] − s u m [ p o s ] = = c n t 1 − j ) ) mmax[i][j]=max(mmax[i][j],mmax[i-1][j]+val_{pre}*(sum[pos]==j)+val_{suf}*(sum[n]-sum[pos]==cnt_1-j)) mmax[i][j]=max(mmax[i][j],mmax[i1][j]+valpre(sum[pos]==j)+valsuf(sum[n]sum[pos]==cnt1j))

t [ p o s ] = = ? t[pos]==? t[pos]==?,即可右可下
m m a x [ i ] [ j ] = m a x ( m m a x [ i − 1 ] [ j ] , m m a x [ i ] [ j − 1 ] ) + v a l p r e ∗ ( s u m [ p o s ] = = j ) + v a l s u f ∗ ( s u m [ n ] − s u m [ p o s ] = = c n t 1 − j ) mmax[i][j]=max(mmax[i-1][j],mmax[i][j-1])+val_{pre}*(sum[pos]==j)+val_{suf}*(sum[n]-sum[pos]==cnt_1-j) mmax[i][j]=max(mmax[i1][j],mmax[i][j1])+valpre(sum[pos]==j)+valsuf(sum[n]sum[pos]==cnt1j)

情况③可以由情况①②表出

最后就是编程上的一些细节:

  • s = " "+s; t = " "+t; 我们在两个字符串前加入空格的原因和棋盘大小的生成原理是一样的,让下标从 1 开始才是我们处理的内容
  • mmax[0][0] = mmin[0][0] = vs*(sum[n]==cnt1); 初始化时如果两字符串后缀 1 ~ n 1~n 1n 是相同的,要计算上这一部分
#include <bits/stdc++.h>

using namespace std;

const int N = 1e3+10;
int n, cnt0, cnt1, vp, vs, pos, mmax[N][N], mmin[N][N], sum[N];
string s, t;

int main()
{
    cin >> n >> cnt0 >> cnt1 >> vp >> vs;
    cin >> s >> t;
    s = " "+s;
    t = " "+t;
    for(int i=1;i<=n;i++)
        sum[i] = sum[i-1]+(s[i]-'0');
    memset(mmax, -0x3f, sizeof(mmax));
    memset(mmin, 0x3f, sizeof(mmin));
    mmax[0][0] = mmin[0][0] = vs*(sum[n]==cnt1);
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            pos = i+j;
            if(t[pos]!='0'&&j)
            {
                 mmax[i][j] = max(mmax[i][j], mmax[i][j-1]+vp*(sum[pos]==j&&pos)+vs*(sum[n]-sum[pos]==cnt1-j&&pos!=n));
                 mmin[i][j] = min(mmin[i][j], mmin[i][j-1]+vp*(sum[pos]==j&&pos)+vs*(sum[n]-sum[pos]==cnt1-j&&pos!=n));
            }
            if(t[pos]!='1'&&i)
            {
                mmax[i][j] = max(mmax[i][j], mmax[i-1][j]+vp*(sum[pos]==j&&pos)+vs*(sum[n]-sum[pos]==cnt1-j&&pos!=n));
                mmin[i][j] = min(mmin[i][j], mmin[i-1][j]+vp*(sum[pos]==j&&pos)+vs*(sum[n]-sum[pos]==cnt1-j&&pos!=n));
            }
        }
    }
    cout << mmin[cnt0][cnt1] << " " << mmax[cnt0][cnt1] << endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值