小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?
一个仅包含'0'和'1'的字符串,长度不超过 2000。
所有非空子串的权值和。
10001
8
长度为 2 的子串中,有 2 个"00"的权值是 1。长度为 3 的 3 个子串权值都是 1。长度为 4 的 2 个子串权值都是 1。长度为 5 的 1 个子串权值是 1。总权值之和为 2+3+2+1=8
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 String st = in.nextLine(); char[] ss = st.toCharArray(); int n = ss.length; // "1": 1; "0": 0 // ss[i][j], [i, j] int[][] weight = new int[n][n]; for (int i = 0; i < n; i++) { if (i % 2 == 1) { weight[i][i] = ss[i]=='1' ? 1: 0; } else { weight[i][i] = ss[i]=='0' ? 1: 0; } } int res = 0; for (int i = 2; i <= n; i ++) { for (int j = 0; j + i - 1 < n; j++) { weight[j][j+i-1] = weight[j][i+j-2] + weight[j+i-1][j+i-1]; res += Math.min( i-weight[j][j+i-1], weight[j][j+i-1]); } } System.out.println(res); } }
import java.util.*; public class Main { static boolean isAchieved; public static void main(String[] args) { Scanner sc = new Scanner(System.in); char[] chars = sc.next().toCharArray(); int n = chars.length; int[][][] dp = new int[n][n][2]; int res = 0; dp[0][0][chars[0] - '0'] = 0; dp[0][0][1 - chars[0] + '0'] = 1; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { if (i == 0 && j == 0) continue; int bit = chars[j] - '0'; dp[i][j][bit] = dp[i][j - 1][1 - bit]; dp[i][j][1 - bit] = dp[i][j - 1][bit] + 1; res += Math.min(dp[i][j][bit], dp[i][j][1 - bit]); } } System.out.println(res); } }