原题; http://codeforces.com/problemset/problem/914/C
题意;x进行变换就会变成2进制中1的个数,对于给的N求1-N的变换k次变成1的个数。
题解:虽然N很大,但是进行一次变换就会变成1000以内的数,不妨暴力预处理出1-1000的变成1的次数。之后考虑数位dp即如何填1。
- 先考虑为1的数位可以填可以填0可以填1,填0的话后面就是一个组合数,直接就能算出来,填1的可以在之后的1算出来
- 考虑为0的数位,假如可以填1,但这一部分被组合算完了,直接跳过就行。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
const int M=1e9+7;
typedef long long ll;
int f[N];
ll fac[N],inv[N];
ll ans;
string str;
int n,k;
int dfs(int x){
if(x==1) return 0;
int cnt=0;
while(x){
if(x&1)cnt++;
x>>=1;
}
return dfs(cnt)+1;
}
ll pow_mod(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%M;
b>>=1;a=a*a%M;
}
return ans;
}
ll c(int n,int m){
if(n<m) return 0;
else return (fac[n]*inv[m])%M*inv[n-m]%M;
}
int main(){
fac[0]=1;
for(int i=1;i<=1000;i++) fac[i]=i*fac[i-1]%M;
inv[1000]=pow_mod(fac[1000],M-2);
for(int i=999;i>=0;i--) inv[i]=inv[i+1]*(i+1)%M;
for(int i=1;i<=1000;i++) {
f[i]=dfs(i);//printf("%d %d\n",i,f[i]);
}
// printf("%d",c(1,1));
ans=0;
cin>>str;n=str.size();
scanf("%d",&k);
ll ans=0;
for(int i=1;i<=n;i++){
if(f[i]==k-1){
int cnt=i;
for(int j=0;j<n && cnt>=0;j++) {
if(str[j]=='1') {
ans=(ans+c(n-j-1,cnt))%M;
cnt--;
// printf("%d %d\n",n-j-1,cnt);
}
}
if(cnt==0) ans++;
}
}
if(k==1) ans--;//
if(k==0) ans=1;
printf("%lld\n",ans);
return 0;
}