给定一个长度为n的01串,定义“连续段"为极长注续的相同字符的数量,例如001110000'有一个长度为2的0连续段,长度为3的1连续段,长度为4的0的连续段。 已知每次操作可以把一个0变成1或者把1变成0。 现在请你用最少的操作欢数,使得所有0连续段的长度都是a的倍数,1连续段的长度都是b的倍数。 输入描述:第一行输人三个正整数n, a, b 第二行输入一个长度为n的,仅有字符0和1构成的字符串,其中1<= n, a, b,<=20000. 输出描述:使得字符串合法的最小操作次数,特殊的,如果无论如何字符串都不能合法,输出-1. 示例:输入 8 2 3 10111000 输出:2. 用java给出代码
时间: 2023-05-26 21:07:44 浏览: 39
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int a = scanner.nextInt();
int b = scanner.nextInt();
String str = scanner.next();
int[] zeroCounts = getContinuousCounts(str, '0'); // 获取0的连续段长度数组
int[] oneCounts = getContinuousCounts(str, '1'); // 获取1的连续段长度数组
int[][] dp = new int[a][b]; // dp[i][j]表示0的连续段长度模a余i,1的连续段长度模b余j的最小操作次数
for (int i = 0; i < a; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE / 2); // 初始化为极大值,避免后面出现越界
}
dp[0][0] = 0; // 初始状态
for (int count : zeroCounts) {
for (int i = 1; i < a; i++) {
int mod = i - count % a;
if (mod < 0) {
mod += a;
}
for (int j = 0; j < b; j++) {
dp[i][j] = Math.min(dp[i][j], dp[mod][j] + count); // 转移方程
}
}
}
for (int count : oneCounts) {
for (int j = 1; j < b; j++) {
int mod = j - count % b;
if (mod < 0) {
mod += b;
}
for (int i = 0; i < a; i++) {
dp[i][j] = Math.min(dp[i][j], dp[i][mod] + count); // 转移方程
}
}
}
int result = Integer.MAX_VALUE / 2;
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
if ((i == 0 && j == 0) || i * b == j * a) { // 符合条件的状态
result = Math.min(result, dp[i][j]);
}
}
}
System.out.println(result == Integer.MAX_VALUE / 2 ? -1 : result);
}
// 获取对于给定字符,连续的长度数组
private static int[] getContinuousCounts(String str, char target) {
List<Integer> counts = new ArrayList<>();
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == target) {
count++;
} else {
if (count > 0) {
counts.add(count);
count = 0;
}
}
}
if (count > 0) {
counts.add(count);
}
int[] result = new int[counts.size()];
for (int i = 0; i < counts.size(); i++) {
result[i] = counts.get(i);
}
return result;
}
}