Problem - 997A - Codeforces
题目:
You've got a string a1,a2,…,ana1,a2,…,an, consisting of zeros and ones.
Let's call a sequence of consecutive elements ai,ai + 1,…, ajai,ai + 1,…, aj (1≤ i≤ j≤ n1≤ i≤ j≤ n) a substring of string aa.
You can apply the following operations any number of times:
- Choose some substring of string aa (for example, you can choose entire string) and reverse it, paying xx coins for it (for example, «0101101» →→ «0111001»);
- Choose some substring of string aa (for example, you can choose entire string or just one symbol) and replace each symbol to the opposite one (zeros are replaced by ones, and ones — by zeros), paying yy coins for it (for example, «0101101» →→ «0110001»).
You can apply these operations in any order. It is allowed to apply the operations multiple times to the same substring.
What is the minimum number of coins you need to spend to get a string consisting only of ones?
Input
The first line of input contains integers nn, xx and yy (1 ≤ n ≤ 300000,0≤x,y≤1091 ≤ n ≤ 300000,0≤x,y≤109) — length of the string, cost of the first operation (substring reverse) and cost of the second operation (inverting all elements of substring).
The second line contains the string aa of length nn, consisting of zeros and ones.
Output
Print a single integer — the minimum total cost of operations you need to spend to get a string consisting only of ones. Print 00, if you do not need to perform any operations.
Examples
5 1 10
01000
11
给定一串0-1序列,定义两种操作:
- 操作一:选取一连续子串倒置。
- 操作二:选取一连续子串把进行01互换(取反)。
- 并给出操作一和操作二的代价,分别为x和y。
操作到最后要把串变成只含1的串,问最小的操作代价。
显然,第一个操作是一个辅助操作,是不能把字符由 1 改到 0 的。只有第二个操作才可以实现 真正的 操作。
ok, 那我们先考虑一个更简单的问题——假如只能做操作二,那么到答案和什么有关呢?
显然, 连续0 的组数决定了答案。 也就是说,有几组0,我们就要进行多少次操作二。那么最后答案也就是 0的组数*操作二的代价 。
现在我们加上操作一。有了操作一我们能做什么呢?
为了叙述方便,我们把操作一的代价设为 x ,操作二的代价设为 y 。
比如 0010010 ,我们有以下三种操作:
1、直接进行三次操作二来得到 11111,最后代价是 3*y。
2、先把 (从左往右数) 第四位 到 第六位 倒置,变成 0011000, 再进行两次操作二就可以了,最后代价为 x+2*y 。
3、先把 (从左往右数) 第四位 到 第六位 倒置,变成 0011000,再把前四位倒置,变成 1100000,最后进行一次操作二。代价和为 2*x+y 。
那么选择哪一个方式呢?
显然,当 y<=x 时,3*y <= x+2*y <= 2*x+y,选择第一种方式代价最小。
而 y>x 时,2*x+y < x+2*y < 3*y,选第三种方式代价最小。
好像明白了些什么...
1、有 cnt组0,那不管怎么操作,怎么组合,都一定需要 cnt 次操作达到目的。即 总操作数一定。
2、不管是操作一还是操作二,进行一次,本质上都可以 消去一组0。而两种操作的唯一不同就在于:第二种操作可以 单独 完成整个任务。而第一种则只能最多进行 (n-1) 次有效操作,使得原字串中所有的 0 挨在一起,成为一组,此后需要再进行一次操作一,才能达到目的。
那就好说了,哪种操作代价少用哪种操作呗。
所以 当 y<=x 时,总代价 ans = cnt*y;
当 x<y 时,总代价 ans = (cnt-1)*x + y;
合在一起: ans = (cnt-1)*min(x,y) + y;
完毕。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 3e5 + 10; typedef long long ll; ll ans; ll x, y, n, cnt, tot; char a[MAXN]; int main(){ a[0]='1';//万一第一位是0呢 scanf("%lld%lld%lld",&n,&x,&y); scanf("%s",a+1); for(int i=1;i<=n;i++){ if(a[i]=='0' && a[i-1]=='1') ++cnt;//记录0的组数 } if(cnt == 0){//特判(题目要求) printf("0");return 0; } ans = (cnt-1)*min(x,y)+y;//如果cnt,x,y不用ll,那么必须强转一下,否则会炸 printf("%lld",ans); return 0; }