问题描述
小S在处理一个安全事故时发现,Cion 勒索病毒攻击了公司的数据库,对数据进行了加密,并且要求支付Cion币来解锁。为了最大化从解锁过程中获得的Cion币,小S可以对留下的01字符串进行操作,但需遵循严格的规则:
- 使用一个
0
替换子串00
,获得a
枚Cion币。 - 使用一个
1
替换子串11
,获得b
枚Cion币。 - 删除一个
0
,支付c
枚Cion币。
操作的难点在于,连续两次操作的编号不能具有相同的奇偶性。
求你可以获得的最大 Cion 币是多少。
测试样例
样例1:
输入:
n = 5, a = 2, b = 2, c = 1, s = "01101"
输出:3
样例2:
输入:
n = 6, a = 4, b = 3, c = 5, s = "110001"
输出:11
样例3:
输入:
n = 6, a = 3, b = 2, c = 1, s = "011110"
输出:4
样例4:
输入:
n = 4, a = 1, b = 3, c = 2, s = "1111"
输出:3
样例5:
输入:
n = 3, a = 2, b = 2, c = 1, s = "000"
输出:2
解题思路
经分析可知,若字符串有连续0或者连续1应尽可能多的进行操作1和操作2,从而可将字符串中的“00”转换为“0”,“11”转换为“1”,如果操作3的支付金额小于操作2的获得金额,对于字符串中“101”的情况可以通过一次操作3和操作2将其转换为“1”,否则不予处理。模拟过程中需留意操作2和操作1、3必须交替进行。
算法步骤
-
初始化变量:
waste0
:用于统计单个0
的数量。count0
:用于统计连续的00
子串的数量。count1
:用于统计连续的11
子串的数量。counts0
:用于存储连续0
的数量。start
:用于标记是否在字符串的开头。count
:用于临时存储连续0
的数量。
-
遍历字符串:
- 从第一个字符开始遍历到倒数第二个字符。
- 如果当前字符和下一个字符都是
0
,则增加count0
或count
的计数。 - 如果当前字符是
0
,但下一个字符不是0
,则将count
添加到counts0
列表中,并重置count
。 - 如果当前字符是
1
,并且下一个字符也是1
,则增加count1
的计数。
-
处理最后一个字符:
- 如果最后一个字符是
0
,则增加waste0
的计数,并更新count0
。
- 如果最后一个字符是
-
计算总收益:
- 计算
total0
,即所有连续0
的数量之和。
- 计算
-
计算最大收益:
- 初始化
maxProfit
为 0。 - 遍历所有可能的操作组合(替换
00
和11
子串的数量)。 - 计算每种操作组合的收益,并根据奇偶性限制选择最优的操作组合。
- 更新
maxProfit
。
- 初始化
-
返回最大收益:
- 返回计算得到的最大收益。
代码实现
import java.util.*;
public class Main {
public static int solution(int n, int a, int b, int c, String s) {
int waste0 = 0, count0 = 0, count1 = 0;
List<Integer> counts0 = new ArrayList<>();
boolean start = true, num1 = false, num0 = false;
int count = 0;
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == '0' && s.charAt(i) == s.charAt(i + 1)) {
if (start)
count0++;
else
count++;
} else if (s.charAt(i) == '0') {
if (start)
waste0++;
else {
counts0.add(count);
count = 0;
}
} else {
start = false;
if (s.charAt(i) == '1' && s.charAt(i) == s.charAt(i + 1)) {
count1++;
}
}
}
if (s.charAt(n - 1) == '0') {
waste0++;
if (!start) count0 += count;
}
int res = 0;
Collections.sort(counts0);
int total0 = count0;
for(int i = 0; i < counts0.size(); i++){
total0 += counts0.get(i);
}
if (c >= b) {
if(count1 > total0) res = total0 * a + total0 * b + b;
else if(count1 == total0) res = total0 * a + total0 * b;
else res = count1 * ( a + b) + a;
} else {
if(count1 > total0 + waste0) res = total0 *(a + b) + b + (waste0 + counts0.size() * (b - c));
else if(count1 > total0) res = total0 *(a + b) + b + (count1 - total0 - 1 +counts0.size() *(b - c));
else if(count1 == total0) res = total0 * a + count1 * b + (counts0.size() *(b - c));
else if(count1 >= total0 - count0) res = count1*(a + b) + a + counts0.size()*(b - c);
else{
for(int i = 0; i < counts0.size(); i++){
int cnt = counts0.get(i);
if(count1 >= cnt){
count1 -= cnt;
res += cnt * (a + b) + b - c;
}
else res += count1 * ( a + b) + a;
}
}
}
return res;
}
}