P10766 「CROI · R2」01-string
P10766 「CROI · R2」01-string
给定长为 \(n\) 的 01 串 \(a_i,b_i\),你可以对 \(a\) 进行若干次如下操作:
- 选定 \([l,r]\),将 \(a_l \sim a_r\) 进行 flip。
- 选定 \([l,r]\),将 \(a_l \sim a_r\) 推平为 \(0\)。
- 选定 \([l,r]\),将 \(a_l \sim a_r\) 推平为 \(1\)。
多测,\(T \le 10\),\(n \le 5\times 10^5\),1 秒,512 MB。
对于只有 flip 操作的情形,问题是 \(\mathbb{F}_2\) 中的序列铲雪:构造 \(c_i=a_i-b_i\),答案为
\[\dfrac{1}{2}\sum_{i=1}^{n+1} |c_i-c_{i-1}|
\]
减法等价于异或 \(\oplus\),故上式计算的是 \(c_i\) 的 \(1\) 连续段数。
还有一些显然的性质:每个位置至多参与推平一次,以及我们可以先推平再 flip。
据此直接写出线性 DP:
- 设 \(f_{0/1/2,i}\) 为满足下列条件的最小操作数:
- 仅考虑 \(1 \sim i\) 位置。
- \(a_i\) 所属的推平段颜色为 \(0/1\),用 \(2\) 表示不操作。
- 转移 \(f_{x',i-1} \to f_{x,i}\)。容易求得 \(c_i\) 和 \(c_{i-1}\),算清楚贡献即可。
- DP 初值为 \(f_{2,0}=0\),其余位置 \(+\infty\)。
- 答案为 \(f_{2,n+1}\)。
复杂度 \(O(n)\)。
const int N = 5e5 + 5;
int n, a[N], b[N], f[3][N];
void _main() {
string s, t; cin >> s >> t, n = s.size();
for (int i = 1; i <= n; i++) a[i] = s[i-1]^48, b[i] = t[i-1]^48;
a[n+1] = b[n+1] = 0;
memset(f, 0x3f, sizeof(f)), f[2][0] = 0;
for (int i = 1; i <= n+1; i++) for (int x : {0, 1, 2})
for (int y : {0, 1, 2}) {
int p = (x == 2 ? a[i] : x) ^ b[i];
int q = (y == 2 ? a[i-1] : y) ^ b[i-1];
chkmin(f[x][i], f[y][i-1]
+ (p == 1 && q == 0)
+ (x != y && y != 2));
}
cout << f[2][n+1] << '\n';
}

浙公网安备 33010602011771号