CodeForces-914C 数位DP

CodeForces-914C 数位DP

题意给一个二进制数n,和整型k,求1-n有多少个数到1的步长是k。

这里的走一步是指, 当前这个数变成二进制位1的个数。比如5->2->1,两步。

n可以很大,但是步长都不会超过1000,预处理出,有x位1的数到1的步长是多少,准备前1000的情况就够用了。

但是dp让我感觉有点不好想,从高位到低位枚举,碰到第i位是1的时候,固定比 i高的位,假设第i位是0,然后可以枚举第位的所有二进制情况。(因为第i位取0,保证了不会超过i)

枚举可以借助组合数优化,枚举1的个数,如果当前个数满足,就把组合的方案数加入到答案。

最后如果不在循环里处理当前位置1补回来的话,最后还要加一下。

要判一下0的特例,还有1的特例。(1到1的步长是0,但是二进制只有一个1的其他数,到1 的步长是1)

里面有一个组合数的模板= =,可能不太好看,不喜欢的话可以自己敲一个。

#define _debug(x) cerr<<#x<<" = "<<x<<endl

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int MAXN = 1e3 + 59;
const int MOD = 1e9 + 7;

template<typename _Tp, const int BCSize, const _Tp Mod> //add Mod as parameter;
struct Binomial_Coefficient {
    _Tp fac[BCSize + 1];
    _Tp inv[BCSize + 1];

    inline Binomial_Coefficient() {    //add Mod as parameter;
        fac[0] = 1;
        for (int i = 1; i <= BCSize; i++)
            fac[i] = fac[i - 1] * i % Mod;

        inv[BCSize] = 52180388;
        // printf inv[BCSize] to get & save it;
        for (int i = BCSize - 1; ~i; i--)
            inv[i] = inv[i + 1] * (i + 1) % Mod;
    }

    inline _Tp operator()(const int &n, const int &m) {
        return fac[n] * inv[m] % Mod * inv[n - m] % Mod;
    }
};

typedef Binomial_Coefficient<long long, 1000, MOD> zuHeShu;
zuHeShu C = zuHeShu();


int kase, Kase;
char s[MAXN];
ll step[MAXN], bits[MAXN], k;
ll dp[MAXN];
int len;

int main() {

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> (s + 1) >> k;

    if (k == 0) {
        cout << 1 << endl;
        return 0;
    }

    for (int i = 1; i <= 1000; i++) {
        bits[i] = bits[i >> 1] + (i & 1);
        step[i] = step[bits[i]] + 1;
    }

    step[1] = 1;
    step[0] = MAXN;

    len = strlen(s + 1);
    int cnt1 = 0;
    for (int i = 1; i <= len; ++i) {
        dp[i] = dp[i - 1];
        if (s[i] == '1') {
            for (int j = 0; j <= len - i; ++j)
                if (step[cnt1 + j] == k)
                    dp[i] = (dp[i] + C(len - i, j)) % MOD;
            cnt1++;
        }
    }
    if (step[cnt1] == k)
        dp[len] = (dp[len] + 1) % MOD;
    if (k == 1)
        dp[len] = (dp[len] + MOD - 1) % MOD;
    cout << dp[len] << endl;
    return 0;
}
/*




 * */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章