题目:
题意:
给出一个正整数
n
n
n ,问你
∏
i
=
1
N
s
u
m
(
i
)
\prod_{i=1}^{N}sum(i)
∏i=1Nsum(i)
p
.
s
.
s
u
m
(
i
)
p.s. sum(i)
p.s.sum(i)为
i
i
i在二进制下时
1
1
1的个数
分析:
对于数
n
n
n来说,必定是
1
—
n
1—n
1—n中最大的这不废话吗
因此,可以有两个引理:
1.
1.
1.在二进制下
t
a
ta
ta的首位
1
1
1一定是出现最早的
2.
2.
2.首位
1
1
1出现的位置后都必定存在
1
1
1
证明:
1.
1.
1.因为
n
n
n是最大的,所以显然(逃
2.
2.
2.假设
n
n
n为
4
4
4,,则在二进制下为
1000
1000
1000,因为我们要求的是
1
—
n
1—n
1—n。所以必定存在一个恰好比
n
n
n少一位并且所有位上的都是
1
1
1,我们成为
s
u
p
e
r
super
super
n
u
m
b
e
r
number
number。在这个例子中,
s
u
p
e
r
n
u
m
b
e
r
super\ number
super number是
3
3
3,即
111
111
111
根据
引
理
1
引理1
引理1,我们得到了需要倒序求解的思路
(
n
2
表
示
(n_2表示
(n2表示n
的
二
进
制
数
)
的二进制数)
的二进制数)
根据
引
理
2
引理2
引理2,我们知道的当
n
2
n_2
n2出现
1
1
1后,之后便可以直接累加
用人话来说,设
f
i
f_i
fi为
1
1
1出现次数恰好为
i
i
i时的方案数(雾不知道怎么正确表达)
随后我们可以得到一个式子:
∑
i
=
n
1
f
[
i
]
+
=
f
[
i
−
1
]
(
其
实
不
需
要
∑
,
只
是
觉
得
这
样
表
示
循
环
比
较
高
级
233
)
\sum_{i=n}^1f[i]+=f[i-1](其实不需要\sum,只是觉得这样表示循环比较高级233)
i=n∑1f[i]+=f[i−1](其实不需要∑,只是觉得这样表示循环比较高级233)
也就是上文说到的累加,当我们遍历多一位时,
1
1
1出现的次数便必然会
+
1
+1
+1
P
.
S
.
P.S.
P.S.因为我们不能保证
n
n
n一定是
s
u
p
e
r
n
u
m
b
e
r
super\ number
super number,所以统计
1
1
1出现的次数时从
0
0
0开始统计,最后再补上一次便不会漏记,且因为我们补得是最后一位,所以不用再进行累加
代码:
// luogu-judger-enable-o2
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define LL long long
#define LZX 10000007
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
using namespace std;
LL ksm(LL x,LL y)
{
LL s=1;
while(y)
{
if(y%2) (s*=x)%=LZX;
y/=2;(x*=x)%=LZX;
}
return s;
}
LL f[55],cnt=0;
int main()
{
LL n=read();
for(LL j=49;~j;j--)
{
for(LL i=49;i;i--) f[i]+=f[i-1];
if(n>>j&1) f[cnt++]++;
}
f[cnt]++;
LL ans=1;
for(LL i=1;i<=49;i++)
(ans*=ksm(i,f[i]))%=LZX;
cout<<ans;
return 0;
}