原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=3209
Time Limit: 10 Sec Memory Limit: 128 MB
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
Source
原创 Memphis
这题可以分别统计出sum=1,sum=2…sum=lg(n)的个数,然后快速幂就可以了。
(一开始我怕cnt数组会炸,把cnt对10000006取模,结果10000007不是质数…)
const
p=int64(10000007);
q=int64(10000006);
mx=60;
var
c:array[0..mx,0..mx] of int64;
d,cnt:array[0..mx] of int64;
n,x,ans:int64;
m,i,j:longint;
procedure dp(w,limit,s:int64);
var
i:longint;
begin
if w<0 then exit;
if (limit=0)or(w=0) then //当前未至上限或者没有数字了都可以直接统计答案
begin
for i:=0 to w do
cnt[s+i]:=cnt[s+i]+c[w][i];
exit;
end;
if d[w]=1
then begin dp(w-1,0,s);dp(w-1,1,s+1);end
else dp(w-1,1,s);
end;
function ksm(d,k:int64):int64;
var
x,t,ans:int64;
begin
x:=d;t:=1;ans:=1;
while t<=k do
begin
if t and k>0
then ans:=(ans*x) mod p;
t:=t<<int64(1);
x:=(x*x) mod p;
end;
exit(ans);
end;
begin
readln(n);
x:=n;m:=0;
while x>0 do
begin
inc(m);
d[m]:=x and int64(1);
x:=x>>int64(1);
end;
for i:=0 to mx do c[i][0]:=1; //c数组是组合数
for i:=0 to mx do c[i][i]:=1;
for i:=2 to mx do
for j:=1 to i-1 do
c[i][j]:=c[i-1][j]+c[i-1][j-1];
fillchar(cnt,sizeof(cnt),0);
dp(m,1,0);
ans:=1;
for i:=1 to mx do
ans:=(ans*ksm(i,cnt[i])) mod p;
writeln(ans);
end.