Description
背景
众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
描述
话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
花神的题目是这样的
设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。
Input
一个正整数 N。
Output
一个数,答案模 10000007 的值。
Sample Input
3
Sample Output
2
HINT
对于样例一,1*1*2=2;
数据范围与约定
对于 100% 的数据,N≤10^15
题解
假设二进制中有\(i\)个1的数的个数为\(s[i]\),那么答案显然是\(\prod i^{s[i]}\)。
\(s[i]\)直接数位\(DP\)就行了。
代码
#include<bits/stdc++.h>
#define MAXN 65
#define LL long long
#define P 10000007
using namespace std;
LL f[MAXN][MAXN],c[MAXN][MAXN],N,cnt,ans=1;
bool bit[MAXN];
LL qp(LL x,LL y){
LL ret=1;
while(y){
if(y&1)ret=ret*x%P;
x=x*x%P;y>>=1;
}
return ret;
}
LL Solve(LL x){//有x个1的数的个数
LL ret=0;
for(int i=cnt;i>=1;i--){
if(bit[i]){
ret+=c[i-1][x];
x--;
}
if(x<0)break;
}
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("bzoj3209.in","r",stdin);
freopen("bzoj3209.out","w",stdout);
#endif
c[0][0]=1;
for(int i=1;i<=64;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++){
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
scanf("%lld",&N);
N++;
while(N){
bit[++cnt]=(N&1);
N>>=1;
}
for(int i=1;i<=cnt;i++)ans=ans*qp(i,Solve(i))%P;
printf("%lld",ans);
return 0;
}