[Luogu] CF1443B Saving the City

\(Link\)

Description

你有一段\(01\)串,你可以选择花费\(B\)的代价将一个\(0\)变为\(1\),也可以花费\(A\)的代价将一段连续的\(1\)变为\(0\),问你最少需要多少代价,才能把整个串都变为\(0\)

Solution

这道题其实不太像\(DP\)

会发现无论对当前点做什么操作,都不会会后面点的选择有影响,即无后效性。

所以对于一段连续的\(1\),我们在最后一个点考虑把它全部消掉的代价。可以用\(A\)直接消掉,也可以把它和下一段连续的\(1\)一起消掉,这时花费为把它们中间的\(0\)都推平的代价(即\(len\times{B}\))。

这样考虑一定是对的。因为对于下一段连续的\(1\),用\(A\)的代价直接消掉,如果之前把它和上一段的\(0\)都推平了,就等于把它们一起消掉,否则就只是花费\(A\)把这一段消掉。

要注意判断这一段\(1\)后面没有\(1\)的情况。

Code

#include <bits/stdc++.h>

using namespace std;

int t, a, b;

char ch[100005];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

int main()
{
	t = read();
	while (t -- )
	{
		a = read(); b = read();
		scanf("%s", ch + 1);
		int l = strlen(ch + 1), res = 0;
		for (int i = 1; i <= l; i ++ )
		{
			if ((ch[i] == '1' && ch[i + 1] == '0') || (i == l && ch[i] == '1'))
			{
				int pos = l + 1;
				for (int j = i + 1; j <= l; j ++ )
				{
					if (ch[j] == '1')
					{
						pos = j;
						break;
					}
				}
				if (pos == l + 1) res += a;
				else res += min(a, (pos - i - 1) * b);
				i = pos - 1;
			}
		}
		printf("%d\n", res);
	}
	return 0;
}
posted @ 2020-11-21 14:57  andysj  阅读(86)  评论(0编辑  收藏  举报