设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你派(Sum(i)),也就是sum(1)—sum(N) 的乘积。
这道题在网上的做法千奇百怪,我来讲一下我的蒟蒻做法,就是普通的数位dp,没用快速幂什么的。定义f[i][j],i不用我讲吧,为位数,j即为枚举到现在1的个数,那之后就是常规做法。值得注意的一点是当枚举到0时(即为没有1),需return 1,不然结果会为0。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define mod 10000007
using namespace std;
int a[61];
long long f[61][61];
long long dfs(int pos,int n1,bool limt)
{
if(pos==0)
{
if(n1==0)return 1;
else return n1;
}
if(limt==false && f[pos][n1]!=-1)return f[pos][n1];
int up=1;long long ans=1;
if(limt==true)up=a[pos];
for(int i=0;i<=up;i++)
{
int s=n1;bool bk=false;
if(i==1)s++;
if(limt==true && i==a[pos])bk=true;
ans=(ans*dfs(pos-1,s,bk))%mod;
}
if(limt==false)f[pos][n1]=ans;
return ans;
}
long long solve(long long x)
{
int pos=0;
while(x!=0)
{
a[++pos]=x%2;
x/=2;
}
return dfs(pos,0,true);
}
int main()
{
memset(f,-1,sizeof(f));
long long n;
scanf("%lld",&n);
printf("%lld\n",solve(n));
return 0;
}