大致题意
这个题意不太好描述啊,直接看原作吧。
思路
然后就可以考虑将两段1的区间合并,中间的0的管道铺设方式改为1的铺设方式。实际变化如下图:
横向的管道可以看作没有变化,不过0的铺设方式会多用两个长度为一的竖向管道,然后支撑管相当于在0铺设方式上删掉了竖向管道,增加了(i-pre-2)个长度为1的支撑管。所以用上述价格差判断一下是否要合并。如果要的话就直接把0改成1,方便后面无脑统计。最后如果1在边缘位置要剪掉1根竖向管道。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define maxm 1000006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int t,n,a,b;
char s[maxn];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&a,&b);
scanf("%s",s+1);
s[n+1]='0';
inc(i,1,n)if(s[i]=='0'&&s[i-1]=='1'&&s[i+1]=='1')s[i]='1';
//inc(i,1,n)printf("%c",s[i]);
//printf("\n");
int pre=0;
inc(i,1,n){
if(s[i]=='1'){
if(pre==0){
pre=i;
continue;
}
if(i-pre>2){
ll cos1=1ll*(i-pre-2)*b;
ll cos2=2ll*a;
if(cos1<=cos2){
inc(j,pre+1,i-1)s[j]='1';
}
}
pre=i;
}
}
int cnt1=0;
int cc=0;
bool flag=0;
inc(i,1,n){
if(s[i]=='1'){
cnt1++;
if(flag==0){
cc++;
flag=1;
}
}
else flag=0;
}
//printf("%d %d\n",cnt1,cc);
int shu=cnt1+cc;
ll ans=1ll*(2ll*shu+n+1-shu)*b;
int heng=n+cc*2;
if(s[1]=='1')heng--;
if(s[n]=='1')heng--;
ans+=1ll*heng*a;
printf("%lld\n",ans);
}
return 0;
}