数位dp(喷血。
如果枚举1的个数,那么这道题可以看做求1−n的二进制表示中有x个1的数字的个数,计算出sum[i] 为恰好有i个的方案数。
设 f[i][j]表示以0开头的 i 位数中1的个数为 j 的数的数量,g[i][j]表示以1开头的 i 位数中1的个数为 jj 的数的数量
则f[i][j]=f[i-1][j]+g[i-1][j],g[i][j]=f[i-1][j-1]+g[i-1][j-1];
然后降维,快速幂求解
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int mod=1e7+7;
lli n,f[65];
inline lli mpow(lli a,lli b)
{
lli c=1;
for (;b;a=(a*a)%mod,b>>=1)
if (b&1) c=(c*a)%mod;
return c;
}
signed main()
{
cin>>n;int tp=0;
for (int i=60;~i;i--)
{
for (int k=60;k>0;k--) f[k]+=f[k-1];
if (n>>i&1) f[tp++]++;
}
f[tp]++;lli ans=1;
for (int i=1;i<=60;i++) ans=(ans*mpow(i,f[i]))%mod;
cout<<ans;
return 0;
}