CF-B - Maximum Cost Deletion

CF-B - Maximum Cost Deletion

题目大意:

​ 给一个长度为n的由01构成的字符串s,和a和b,每次可以删除仅由0或1组成的子串,每次删除获得分数points = a * len + b,len是删除子串的长度。问将s删光后得到的最大得分是多少。

思路:

讲道理题目样例不给这个-2我还真没注意有负数的情况

​ 观察一下每次加分的式子 p = a * len + b,不管每次删除的子串怎么取,最后删光了就是说若干个p加起来,p_total = a * (len1 + len2 + len3 +…+ lenk) + k * b ,k是删除的次数,而len1到lenk的累加,和就是s的总长n,所以最后的p_total 就等于:a * n + k * b ,就是说最后的答案只和删除次数k有关。要使p_total最大,有如下两种情况:

​ 1、b > 0,k尽量大就行,k最大是n(一个一个删)

​ 2、b < 0,k尽量小

接下来对情况2仔思考一下,因为可以删掉子串,所以“00000”和“0”是一样的(都只要删一次),所以可以把连续相同的数都换成一个,可以说是把字符串s“压缩一下”,例如“100011001”变成“10101” 。而这样就只有两种情况,num1 == num0 和 num1 != num0,若不等于则选择数量少的,因为数量少的肯是被夹在中间的,如上面例子中的0 。把数量少的删掉用掉的次数就少了(贪就完事了

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 2*1e8+10;

ll solve(){
	ll ans = 0;
	ll n,a,b;
	string s;
	cin>>n>>a>>b>>s;
	
	if(b > 0)
		return (a + b) * n;
	
	ans = a * n;
	
	string t  = ".";
	ll num[2] = {};
	
	for(int i = 0 ; i < s.length() ; i ++){
		if(t[t.length() - 1] != s[i]){
			t += s[i] ;
			num[s[i] - '0']++;
		}
	}

	return ans + (min(num[0] , num[1]) + 1) * b;
}

int main(){
	ios::sync_with_stdio(false);
	ll T;
	cin>>T;
	while(T -- ){
		cout<<solve()<<"\n";
	}
}

小结:

在做了这个东西后做这个题目就不知道为什么感觉没什么难度

posted @ 2021-09-02 00:13  tyrii  阅读(57)  评论(0)    收藏  举报