1 条题解

  • 0
    @ 2025-8-24 22:55:19

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar TernaryTree
    ?steal a life

    搬运于2025-08-24 22:55:19,当前版本为作者最后更新于2024-02-17 18:00:10,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    类似的题在 CF 好像叫做 Balanced String 来着。0101 序列任意交换都要典成土了。

    首先考虑一个 0101 序列 ss 通过任意交换变成 tt 的最小次数是多少。显然我们一次可以将一对 ss 中的子序列 0101tt 中对应位置的一个 1010(或相反,ss 中的 1010tt 中的 0101)交换,这样一下子减少了 22 个不同的位置。所以最小次数是 $\dfrac12\operatorname{popcount}(s\operatorname{xor} t)$。

    问题转换为,找一个 0101 序列满足题目的条件,并且与 ss 不同的位置最少。

    直接考虑 dp。fi,j,k,0/1f_{i,j,k,0/1} 表示前 ii 位,填了 jj11,最后一个极长 11 连续段长为 kk,第 ii 位填的 0/10/1 的最少不同位置数。

    则有转移:

    $$\begin{aligned} f_{i,j,k,0}&=[s_{i}\neq 0]+\min(f_{i-1,j,k,0},f_{i-1,j,k,1})+\\ f_{i,j,k,1}&=\left(\sum_{p=i-k+1}^i [s_i\neq1]\right)+\min_{l=0}^{k-1}f_{i-k,j-k,l,0} \end{aligned} $$

    第一个式子 Θ(1)\Theta(1) 转移,第二个式子前面一项前缀和即可,后面一项维护 dp 数组前缀 min\min 即可。

    然后可以对第三维滚动数组。空间降为 Θ(n2)\Theta(n^2)

    时间复杂度 Θ(n3)\Theta(n^3)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 810;
    
    int n, m, ans;
    char s[maxn];
    int t[maxn];
    int f[maxn][maxn][2];
    int tmpf[maxn][maxn][2];
    int g[maxn][maxn];
    int tmpg[maxn][maxn];
    
    signed main() {
        cin >> s + 1, n = strlen(s + 1);
        for (int i = 1; i <= n; i++) m += s[i] - '0', t[i] = t[i - 1] + s[i] - '0';
        memset(f, 0x3f, sizeof(f));
        memset(g, 0x3f, sizeof(g));
        memset(tmpf, 0x3f, sizeof(tmpf));
        memset(tmpg, 0x3f, sizeof(tmpg));
        ans = f[0][0][0];
        f[0][0][0] = 0;
        g[0][0] = 0;
        for (int k = 0; k <= m; k++) {
        	for (int i = 1; i <= n; i++) {
    	        for (int j = 0; j <= m; j++) {
                    f[i][j][0] = min(f[i - 1][j][0], f[i - 1][j][1]) + (s[i] == '1');
                    if (k && k <= i && k <= j) f[i][j][1] = tmpg[i - k][j - k] + k - t[i] + t[i - k];
               		if (k) g[i][j] = tmpg[i][j];
                    g[i][j] = min(g[i][j], f[i][j][0]);
    	        }
    	    }
    	    for (int i = 0; i <= n; i++) {
    	        for (int j = 0; j <= m; j++) {
                    tmpf[i][j][0] = f[i][j][0];
                    tmpf[i][j][1] = f[i][j][1];
                    tmpg[i][j] = g[i][j];
    	        }
    	    }
    	    ans = min(ans, f[n][m][0]);
            ans = min(ans, f[n][m][1]);
    	}
        cout << ans / 2 << endl;
        return 0;
    }
    
    • 1

    信息

    ID
    9808
    时间
    1000ms
    内存
    32MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者