题意
求使得所有子串相邻字符都不同的情况下,修改的最小操作次数。
思路
对于任意一个 01 串,最终变成的是 01010101…
或 10101010…
。
是否可以枚举改变的位,然后求包含它子串的个数,然后把这个个数加入到对答案的贡献呢?
答案是不行的。
例如 1110000111
,可以变成 1010101010
或 0101010101
。但无论哪种情况,局部变化的结果不一定是全局的结果。对于这个数据,s[3..5] = '000'
和 s[4..6] = '000'
,应该变成 010
是最小操作次数,但是在上述两种情况中不能同时满足。
所以只能考虑最朴素的 枚举。
枚举所有的子串,这个子串是变成 1 开头的 01 串还是变成 0 开头的 01 串,取操作次数最小的。
可以使用 前缀和 优化求区间操作的次数。
记 pre1
为以 i
为结尾变成 0 开头的 01 串的操作次数,pre2
为以 i
为结尾变成 1 开头的 01 串的操作次数。具体参见代码。
import java.io.*;
import java.math.BigDecimal;
import java.util.Random;
import java.util.Scanner;
import java.util.StringTokenizer;
import static java.util.Arrays.deepToString;
public class Main {
static boolean LOCAL = Boolean.parseBoolean(System.getenv("LOCAL"));
static boolean TO_FILE = Boolean.parseBoolean(System.getenv("LOCAL"));
static Scanner sc = new Scanner(System.in);
static void debug(Object... os) {
System.err.println(deepToString(os));
}
public static void main(String[] args) {
if (LOCAL) {
try {
System.setIn(new FileInputStream("./data/in.txt"));
} catch (Throwable e) {
LOCAL = false;
}
}
if (TO_FILE) {
try {
System.setOut(new PrintStream("./data/output.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
InputReader in = new InputReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
Task solver = new Task();
solver.solve(in, out);
out.close();
}
static class Task {
Random random = new Random(751454315315L + System.currentTimeMillis());
static final int MAXN = (int)1e6 + 10;
static final long INF = (long)1e18;
static final double EPS = 1e-7;
static final double PI = Math.acos(-1.0);
static final long MOD = (long)1e9 + 7;
public void solve(InputReader in, PrintWriter out) {
int t = 1;
// t = in.nextInt();
while (t-- > 0) {
solveSingle(in, out);
}
}
public void solveSingle(InputReader in, PrintWriter out) {
String s = in.nextLine();
int n = s.length();
String t1, t2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append(i % 2);
t1 = sb.toString();
sb.setLength(0);
for (int i = 0; i < n; i++) sb.append((i + 1) % 2);
t2 = sb.toString();
int[] pre1 = new int[n + 1], pre2 = new int[n + 1];
for (int i = 0; i < n; i++) {
pre1[i + 1] = pre1[i];
pre2[i + 1] = pre2[i];
if (s.charAt(i) != t1.charAt(i)) pre1[i + 1]++;
if (s.charAt(i) != t2.charAt(i)) pre2[i + 1]++;
}
long ans = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
ans += Math.min(pre1[j + 1] - pre1[i], pre2[j + 1] - pre2[i]);
}
}
out.println(ans);
}
}
static class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public float nextFloat() {
return Float.parseFloat(next());
}
public BigDecimal nextBigDecimal() { return new BigDecimal(next()); }
public String nextLine(){
while (tokenizer == null || !tokenizer.hasMoreElements()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e){
e.printStackTrace();
}
}
return tokenizer.nextToken("\n");
}
}
}
复杂度分析
- 时间复杂度:
,其中
是字符串的长度。
- 空间复杂度:
,其中
是字符串的长度。