01限定串(传纸条模型)⭐

题目描述

我们称两个字符串是相似的,当且仅当它们的成分相同,并且组成各成分出现的数目相同。例如字符串"abbcdf"与字符串"bcfdab"就是相似的,而"abbcdf"与"abcdf"不相似,因为它们虽然成分相同,但是各成分出现的次数不同。

牛牛本来有两个长度均为n的01字符串s,t,但是t串由于数据损坏,导致一些位置不确定到底是0还是1,不过好在,牛牛清楚的记得t串中有\(cnt_{0}\)个0, \(cnt_{1}\)个1

接下来牛牛要还原损坏的t串。

s串和t串每存在一个非空相似前缀得分\(val_{0}\), 每存在一个非空相似后缀得分\(val_{1}\)

想要知道它能够还原的t串中的最小得分与最大得分。

输入描述:

第一行输入五个整数n \(cnt_{0}\) \(cnt_{1}\) \(val_{0}\) \(val{1}\)

接下来输入两行表示字符串s,t,|s|=|t|=n, n<= 100

其中,s串完全由'0','1'组成,t串完全由'0','1','?'组成。

?表示损坏的部分,也就是需要你还原的部分。

输入数据保证至少存在一种合法的方案。

输出描述:

请输出两个整数,表示还原后的最小得分与最高得分。

示例1

输入

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

输出

0 4

说明

可以构造01串t="00011000"达到最小得分(与s串没有相似的前缀与后缀)
可以构造01串t="00000011"(4个相似的后缀)达到最大得分。

示例2

输入

20 1 19 55 97
11111010101111111111
1?????1?1?1????????1

输出

566 1439

说明

最小:"11111111111111111101"
最大:"11111111101111111111"

示例3

输入

1 0 1 -999 1000
0
?

输出

0 0

说明

因为限制条件为必须有1个1,所以?处只能填1

题解

本题给定了0和1的数量,让你如何排列才能使分数最优。

我们先考虑问题的简单版本,如果给定字符串t全为问号,即对组成的字符串不加限制,就转变经典传纸条问题,

即只求一条从(0,0)到(cnt0,cnt1)的路径,只能向右或向下走,使得路径上的点的权值和最大。

显而易见的变化中的量就是坐标(x,y),用dp[x][y]来表示传到(x,y)这个坐标的时候,最大(小)的权值和

就是普通的传纸条模型

但是有的位置给定了你方向(t[i] != '?'), 分四种情况就行

传统传纸条是

for (int step = 1; step <= n; ++step)
      for (int i = 0; i <= a; ++i)
      {
            int j = step - i;
            if (判断状态是否合法) continue;
            ...
      }

但是注意到后效性

也可以直接二维枚举

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;

const int maxn = 1e3 + 5;

int n, a, b, x, y;
int sum[maxn << 1], f1[maxn][maxn], f2[maxn][maxn];
string s,t;

int main()
{
    cin >> n >> a >> b >> x >> y >> s >> t;
    s = " " + s; t = " " + t;
    rep(i, 1, n) sum[i] = sum[i - 1] + s[i] - '0',

    memset(f1, 0xcf, sizeof f1); memset(f2, 0x3f, sizeof f2);
    f1[0][0] = f2[0][0] = y * (sum[n] == b);

    rep (i, 0, n)
        rep (j, 0, n)
        {
            int pos = i + j;
            int cur = x * (sum[pos] == j && pos) + 
                y * (sum[n] - sum[pos] == b - j && pos != n);
        
            if (t[pos] != '0' && j)
            {
                f1[i][j] = max(f1[i][j], f1[i][j - 1] + cur);
                f2[i][j] = min(f2[i][j], f2[i][j - 1] + cur); 
            }

            if (t[pos] != '1' && i)
            {
                f1[i][j] = max(f1[i][j], f1[i - 1][j] + cur);
                f2[i][j] = min(f2[i][j], f2[i - 1][j] + cur); 
            }
        }
     
    cout << f2[a][b] << " " << f1[a][b] << endl;
    return 0;
} 
posted @ 2020-05-11 20:32  洛绫璃  阅读(186)  评论(0编辑  收藏  举报