题目链接
题目大意:
现在有一个长度为n的字符串 0 1,要将这个字符串全都弄成1,现在可进行两种操作,有两种花费,
分别是,花费x,将字符串中某一连续字符串顺序颠倒;花费y将字符串中某一连续字符串按位取反
思路:
任何一段0 1序列都可以看做是一串 0 然后用 1 切割开。首先,因为我们是要把目标串变成全1串,所以开头的1(和结尾的1)我们可以不去管它,所以我们可以把所有的串看做是这种(开头的1和结尾的1无所谓就全都省略)然后我们可以怎么做呢?例如:000 1000 10000 100 100这个串,因为上面操作的花费与段的长度无关,所以我们可以把相邻的1合成一个1,相邻的0合成一个0。所以原串就可以转化成 0 10 10 10 10。
假设0分成的段的数量是num。
第一种方法,我们可以选择第二段 10 ,对其进行倒置操作,所以整个串就变成了 0 01 10 10 10。然后再次合并相邻的1 和相邻的 0 ,原串变成了 0 10 10 10。然后在进行一次相同的操作,就变成了 0 10 10.以此类推,最后将变成 0 10,再倒置一次,变成 00 1,然后再对00 进行一次操作二即可。这种方法的花费为 (num-1)*x+y。
第二种方法,我们直接对每一段0实施操作二,使得其变为全1串,这样的花费是num*y。
所以显然,当x<=y时,我们选择第一种方案,当x>y时,我们选择第二中方案,统计0的段数,直接输出结果即可。
分析参考自:https://blog.csdn.net/weixin_42165981/article/details/81264009
大神的代码貌似写错了。。。
代码:
#include<iostream>
#include<cstdio>
#define maxn 300005
using namespace std;
char s[maxn];
int main()
{
int n,x,y;
cin>>n>>x>>y;
cin>>s;
int p=0;
for(int i=0; i<n; i++)
if(s[i]=='0')
p++;
if(p==0)
{
cout<<"0"<<endl;
return 0;
}
long long ans=0;
if(x>=y)
{
for(int i=1; i<n; i++)
{
if(s[i-1]=='0'&&s[i]=='1')
ans+=y;
}
if(s[n-1]=='0')
ans+=y;
cout<<ans<<endl;
return 0;
}
else
{
if(s[0]=='0')
p=1;
else
p=0;
for(int i=1; i<n; i++)
if(s[i]=='0')
{
p++;
if(p>1&&s[i-1]=='1')
ans+=x;
}
ans+=y;
cout<<ans<<endl;
return 0;
}
return 0;
}