1 条题解

  • 0
    @ 2025-8-24 21:43:32

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar fy0123
    **

    搬运于2025-08-24 21:43:32,当前版本为作者最后更新于2017-10-19 13:47:01,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    这题是个dp。

    定义方程f[i][j]表示从n~i,用了j个0的方案数。要n~i倒着处理是为之后的第k大做帮助。

    第一问就直接dp,我们记录下p0[i],p1[i]分别表示从左往右第i个0的位置,第i个1的位置。转移的时候根据当前位放0还是放1,且是否满足距离小于等于d,计算即可。

    然后对于第二问,我们这么做:

    • 如果当前位置放0的方案数>=k,当前位就放0。

    • 如果不能放0,就放1,并且k减去放0的方案数。

    以上所有说的可以放0或放1都是建立在题目要求的前提下的,即距离不超过d

    然后我们有一个问题了:如果方案数超过k的超过太多了怎么办?按照题意来说我们应该是要%10^8的,但是由于要求后面的第k大需要用到这个方案数,如果我们直接%10^8,就会导致结果不正确了。

    对于这个问题我们再开一个g[i][j]也记录方案数,如果g[i][j]>10^8了就把它设成10^8+1,然后之后算第k大的时候就用g[i][j]当做方案数,这样就没事了。

    下面放代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 2010;
    const int MOD = 1e8;
    int n, d, k, cnt0 = 0, cnt1 = 0;
    int p0[N], p1[N], f[N][N], g[N][N];
    char s[N];
    
    int main()
    {
        scanf("%d%d%d", &n, &d, &k);
        scanf("%s", s+1);
        for (int i = 1; i <= n; i ++)
            if (s[i] == '0') p0[++ cnt0] = i;
            else p1[++ cnt1] = i;
        f[n+1][0] = g[n+1][0] = 1;
        for (int i = n; i >= 1; i --)
            for (int j = 0; j <= min(n-i+1, cnt0); j ++){
                int k = n-i+1-j;
                if (j && abs(p0[cnt0-j+1]-i) <= d){
                    f[i][j] += f[i+1][j-1];
                    if (f[i][j] > MOD) f[i][j] -= MOD;
                    g[i][j] = min(g[i][j]+g[i+1][j-1], MOD+1);
                }
                if (k && abs(p1[cnt1-k+1]-i) <= d){
                    f[i][j] += f[i+1][j];
                    if (f[i][j] > MOD) f[i][j] -= MOD;
                    g[i][j] = min(g[i][j]+g[i+1][j], MOD+1);
                }
            }
        printf("%d\n", f[1][cnt0]);
        int s0 = cnt0, s1 = cnt1;
        for (int i = 2; i <= n; i ++){
            if (s0 && abs(p0[cnt0-s0+1]-i+1) <= d){
                if (g[i][s0-1] >= k) s0 --, putchar('0');
                else s1 --, k -= g[i][s0-1], putchar('1');
            } else s1 --, putchar('1');
        }
        if (s0) putchar('0'); else putchar('1');
        return 0;
    }
    
    • 1

    信息

    ID
    1994
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者