[Luogu] CF1443B Saving the City
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;
}