#include <stdio.h>
int main()
{
puts("转载请注明出处谢谢");
puts("http://blog.csdn.net/vmurder/article/details/43370607");
}
题解:
数位DP无疑。注:下面说的位基本都是二进制。
f[i][j]表示前i位数中有j个1的数的数量(包括0哦~)
然后一个低位数后面填0/1分别是两种向高位的转移,这样在O(log^2 n)时间内处理出f
主要是我的姿势(嗯,我叫它数位树):
我是把一个大段像线段树一样分成一个个小段,一旦遇到一个完整的段就可以O(1)计数(这里是logn,因为是记录了有i个1的数的个数),然后不完整的就向下一位看,直到完整。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 200
#define MOD 10000007
using namespace std;
long long n,ans[N];
long long f[N][N],len;
long long power(long long x,long long k)
{
long long ret=1;
while(k)
{
if(k&1)ret=ret*x%MOD;
x=x*x%MOD,k>>=1;
}
return ret;
}
void get(int have,long long x,int l)
{
int i,j,k;
if(x==1)ans[have+1]=(ans[have+1]+1)%MOD;
if(x<=1)
{
ans[have]=(ans[have]+1)%MOD;
return ;
}
if(!l)return ;
if(x>=(1<<l-1))for(i=0;i<=60;i++)ans[i+have]=(ans[i+have]+f[l-1][i])%MOD;
if(x==(1<<l))for(i=0;i<=60;i++)ans[i+have+1]=(ans[i+have+1]+f[l-1][i])%MOD;
else if(x<(1<<l-1))get(have,x,l-1);
else get(have+1,x-(1<<l-1),l-1);
}
int main()
{
int i,j,k;
scanf("%lld",&n);
while(n>>len)len++;
for(i=0;i<=len;i++)
{
f[i][0]=1;
for(j=1;j<=i;j++)f[i][j]=f[i-1][j-1]+f[i-1][j];
}
get(0,n,len);
long long print=1;
for(i=2;i<=60;i++)print=print*power(i,ans[i])%MOD;
cout<<print<<endl;
return 0;
}