题目链接

https://codeforces.com/contest/1443/problem/B

解题思路

也算是dp吧。
转移(抽象讲解):
对于每个连通块(特指为1),无非是选择单独引爆,或者选择与前面的连通块相连通。
dp[i]表示引爆前i个连通块的最小花费,那对于第i个连通块而言,选择单独引爆时dp[i]=dp[i-1]+a;选择与前面的连通块连通引爆时,由于dp[i-1]表示的就是前i-1个引爆的最小花费,所以其实对于第i个连通块来说,只需要与前面的连通块相连,不需要再加上引爆的费用了,而连通的费用就是第i个连通块前面相邻的0的个数*b。

AC代码

#include<bits/stdc++.h>
#define int long long
const int N=1e5+100;
const int inf=0x3f3f3f3f;
using namespace std;
int T,a,b,n,cnt,cnt0,cnt1;
string str;
vector<int> cnttt0,cnttt1;//cnttt0[i]表示第i个0连通块的0的个数;cnttt1[i]表示第i个1连通块的1的个数。
int dp[N];
signed main()
{
    cin>>T;
    while(T--)
    {
        cin>>a>>b;
        cin>>str;
        n=str.size();
        str=' '+str;
        cnttt0.clear();
        cnttt1.clear();
        for(int i=1;i<=n;i++)
        {
            cnt1=0,cnt0=0;

            if(i==1 && str[i]=='0')
            while(i<=n && str[i]=='0') i++;//清除前导0

            while(i<=n && str[i]=='1') cnt1++,i++;    
            if(cnt1) cnttt1.push_back(cnt1);//统计1连通块

            while(i<=n && str[i]=='0') cnt0++,i++;
            if(cnt0) cnttt0.push_back(cnt0);//统计0连通块

            i--;
        }

        dp[0]=a;//初始化,如果就一个1连通块时
        for(int i=1;i<cnttt1.size();i++)
        dp[i]=min(cnttt0[i-1]*b+dp[i-1],dp[i-1]+a);

        cout<<dp[cnttt1.size()-1]<<endl;    
    }
}