CF #493(div2) C(略水)

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;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/80904152