description:
给出一个01串,现在可以任选其中的一个连续子串做两种操作。
第一种:从该01串中把该子串取出倒置后再插回去,消耗x
第二种: 把该子串中的所有元素取反,消耗y
求把整个串变成全1串所需的最小费用。
input:
给出一个n, x,y 的值。接下来是一个长度为n的01串
output:
最小消费值
analysis:
首先根据题目的数据量和限制时间可以知道需要大致O(n)的复杂度。这样也就需要对问题进行更多的分析。
观察发现,这个问题中原本就连在一起的0或1至始至终都是连在一起的,不论是进行操作1还是2,把原本连在一起的1或是0分隔开是绝对不划算的。因为这样做的话,至少会多出一个全是0的子串,而每次操作至多只能消去一个全0子串,这也就意味着该次分隔操作是无意义的。如此看来,原01串中连续的元素之间是可以在一开始就缩为一个元素的。比如00011011直接就可以缩为0101. 也就是说问题转化为给出一个01交替出现的串,问进行以上两种操作所需最小花费。
不难看出 如果用a次操作1加一次操作2可以消除a+1个0,消费ax+y。直接用(a+1)次操作2同样可以消去a+1个0,消费(a+1)y。直接输出小的费用就行。注意特殊情况。
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1 << 30;
const int maxn = 300005;
const int MOD=1e9+7;
int n,x,y;
int main()
{
//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
char s[maxn];
int cnt[2];
while(~scanf("%d%d%d",&n,&x,&y)){
scanf("%s",s);
memset(cnt,0,sizeof(cnt));
int head=-1;
for(int i=0;i<n;++i){
if(head==-1){head=s[i]-'0';cnt[head]++;}
if(head==s[i]-'0'){
continue;
}
else{
head^=1;
cnt[head]++;
}
}
LL ans=max(min(1ll*cnt[0]*y,y+1ll*(cnt[0]-1)*x),0ll);
printf("%lld\n",ans);
}
return 0;
}