题目描述
我们称两个字符串是相似的,当且仅当它们的成分相同,并且组成各成分出现的数目相同。例如字符串"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;
}