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';
}
posted @ 2026-10-29 15:46  stripe_python  阅读(8)  评论(0)    收藏  举报