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;
}
/*
* */