题目链接
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;
}
}

京公网安备 11010502036488号