对于一个正整数x,我们定义一次操作是将其变为它二进制下“1”的个数,比如我们知道13(10)=1101(2),而1101有三个"1",所以对13进行一次操作就会将其变为3。显而易见的是,对于一个正整数,我们在进行若干次操作后,一定会将其变为1。
给定n和k,其中n是在二进制下被给出,求出所有不大于n且将其变为1的最小操作次数为k的数的个数对10^9+7取模的结果。
因为strlen(str) <= 1000, 使用在预处理1-1000中变化到1时要多少步,中枚举1-1000,然后使用组合数学()
#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1005;
char str[maxn];
int dp[maxn], m;
int getbit(int x) {
int ans = 0;
while (x) {ans += x % 2; x /= 2;}
return ans;
}
int C[maxn][maxn];
void init() {
for(int i = 0; i <= 1000; ++i)
C[i][0] = 1;
for(int i = 1; i <= 1000; ++i) {
for(int j = 1; j <= 1000; ++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
/*
*
*/
int main() {
// freopen("in.in", "r", stdin);
init();
cin >> str + 1;
strrev(str + 1);
int n = strlen(str + 1);
cin >> m;
int ans = 0;
if (m == 0) {cout << "1" << endl; return 0;}
for(int i = 2; i <= 1000; i++) dp[i] = dp[getbit(i)] + 1;
for (int i = 1; i <= 1000; i++) {
if (dp[i] != m - 1) continue;
int cnt = 0;
for (int j = n, k = i; j >= 1; j--) {
if (str[j] == '0') continue;
if (k == 1) { //这个地方要特别注意一下,因为就剩下最后一个1,所以1-j个位子都可以放1
ans = (ans + C[j][1]) % mod; break;
}
if (j - 1 >= k ) ans = (ans + C[j - 1][k]) % mod; k--;
}
}
if (m == 1) {
ans = (ans - 1 + mod) % mod;
}
cout << ans << endl;
return 0;
} 
京公网安备 11010502036488号