1. 程式人生 > 實用技巧 >[Luogu] CF1443B Saving the City

[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;
}