题解 Luogu P3048 【[USACO12FEB]牛的IDCow IDs】

题目链接:LuoguP3048

做法:\(dp\) + 递归。

首先,我们可以发现,排名为 \(N\) 的奶牛编号位数一定不超过 \(5 \times 10^3\),故,我们可以使用位数来解决此题。

我们设 \(f_{i,j}\) 表示在前 \(i\) 位上放 \(j\)\(1\) 的方案数,转移则为 \(f_{i,j} = f_{i-1,j} + f_{i - 1,j - 1}\) ,也就是分成 \(2\) 种情况:新增加进来的那位数为 \(0\)\(1\)\(2\) 种情况。

然后递归求解,对于第 \(step\) 个位置,我们可以选择填 \(1\) 或填 \(0\),若当前的排名大于所有长度比它小 \(1\) 且满足条件的编号的方案数,则当前位置填 \(1\) 否则则填 \(0\)
然后由于首位必须为 \(1\),所以用个 \(opt\) 记录是否有 \(1\) 存在过,在 \(opt\)\(0\) 时,就不能输出 \(0\)

\(Code:\)

#include <bits/stdc++.h>

const int MaxN = 5e3;
const int MaxK = 10 + 10;

using namespace std;

inline int read() {
    int cnt = 0, opt = 1;
    char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar())
        if (ch == '-') opt = 0;
    for (; ch >= '0' && ch <= '9'; ch = getchar())
        cnt = (cnt << 3) + (cnt << 1) + (ch ^ 48);

    return opt ? cnt : -cnt;
}//快读优化

int N, K, opt;

int f[MaxN + 10][MaxK];

inline void dfs(int x, int y, int step) {
    if (! step) return;
    if (x <= f[step - 1][y]) {//不选
        if (opt) putchar('0');
        dfs(x, y, step - 1);
    }
    else {//选
        putchar('1'); opt = 1;
        dfs(x - f[step - 1][y], y - 1, step - 1);
    }
}

int main() {
    N = read(), K = read();
    if (K == 1) {
        putchar('1');
        for (int i = 1; i < N; ++ i) putchar('0');
        return 0;
    }//特判 K 为 1 的情况
    for (int i = 0; i <= MaxN; ++ i)
        f[i][0] = 1;
    for (int i = 1; i <= MaxN; ++ i)
        for (int j = 1; j <= K; ++ j)
            f[i][j] = min((int)1e7, f[i - 1][j - 1] + f[i - 1][j]);//预处理f数组
    dfs(N, K, MaxN);//递归处理
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chz-hc/p/12340263.html