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";
}
}
小结:
在做了这个东西后做这个题目就不知道为什么感觉没什么难度

浙公网安备 33010602011771号