牛客:牛牛的01限定串

题目链接:https://ac.nowcoder.com/acm/contest/5531/D

题目描述:

对于一个长度为n的字符串S,我们称字符串s0s1s2…si为字符串的一个前缀,称字符串si+1si+2…sn为字符串的一个后缀。我们称两个字符串是相似的,当且仅当它们的成分相同,并且组成各成分出现的数目相同。例如字符串"abbcdf"与字符串"bcfdab"就是相似的,而"abbcdf"与"abcdf"不相似,因为它们虽然成分相同,但是各成分出现的次数不同。

牛牛本来有两个长度均为n的01字符串s,t,但是t串由于数据损坏,导致一些位置不确定到底是0还是1,不过好在,牛牛清楚的记得t串中有cnt0个0和cnt1个1。接下来牛牛要还原损坏的t串。
s串和t串每有一个非空前缀相似,就得到val{pre}的得分, 不一定是一个正数,当它的值为负时表示失去val_{pre} 的得分
s串和t串每有一个非空后缀相似,就得到val_{suf}的得分,(val_{suf}
不一定是一个正数,当它的值为负时表示失去val_{suf}的得分) 牛牛想要知道它能够还原的t串中的最小得分与最大得分。

思路:

可以看成是走边长为cnt1和cnt0的纸条问题,然后用动态规划即可

AC代码:

#include
#include
#include

using namespace std;
string s, t;
int n, cnt0, cnt1, vp, vs;
int sum[1005];
int maxn[1005][1005];
int minx[1005][1005];

int main()
{
	int i, j;
	cin >> n >> cnt0 >> cnt1 >> vp >> vs;
	cin >> s >> t;
	s = ' ' + s;
	t = ' ' + t;
	sum[0] = 0;
	for (i = 1; i <= n; i++)
	{
		sum[i] = sum[i - 1] + (s.at(i) - '0');
	}

	memset(maxn, -0x3f, sizeof maxn);
	memset(minx, 0x3f, sizeof minx);

	maxn[0][0] = minx[0][0] = vs * (cnt1 == sum[n]);
	for (i = 0; i <= n; ++i)
	{
		for (j = 0; j <= n; ++j)
		{
			int pos = i + j;
			if (pos > n)
				break;
			if (t[pos] != '1' && i)
			{
				maxn[i][j] = max(maxn[i][j], maxn[i - 1][j] + (sum[pos] == j && pos) * vp + (sum[n] - sum[pos] == cnt1 - j && pos != n) * vs);
				minx[i][j] = min(minx[i][j], minx[i - 1][j] + (sum[pos] == j && pos) * vp + (sum[n] - sum[pos] == cnt1 - j && pos != n) * vs);
			}
			if (t[pos] != '0' && j)
			{
				maxn[i][j] = max(maxn[i][j], maxn[i][j - 1] + (sum[pos] == j && pos) * vp + (sum[n] - sum[pos] == cnt1 - j && pos != n) * vs);
				minx[i][j] = min(minx[i][j], minx[i][j - 1] + (sum[pos] == j && pos) * vp + (sum[n] - sum[pos] == cnt1 - j && pos != n) * vs);
			}
		}
	}
	cout << minx[cnt0][cnt1] << " " << maxn[cnt0][cnt1] << endl;
	return 0;
}

/*
8 6 2 1 1
10110011
????????
*/

你可能感兴趣的:(动态规划,思维)