花 神 的 数 论 题 花神的数论题 花神的数论题
题目链接: l u o g u P 4317 luogu\ P4317 luogu P4317
题目背景
众所周知,花神多年来凭借无边的神力狂虐各大 O J OJ OJ、 O I OI OI、 C F CF CF、 T C TC TC、 … … …… …… 当然也包括 C H CH CH 啦。
题目
话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。 花神的题目是这样的:设 sum ( i ) \text{sum}(i) sum(i) 表示 i i i 的二进制表示中 1 1 1 的个数。给出一个正整数 N N N ,花神要问你 ∏ i = 1 N sum ( i ) \prod_{i=1}^{N}\text{sum}(i) ∏i=1Nsum(i),也就是 sum ( 1 ) ∼ sum ( N ) \text{sum}(1)\sim\text{sum}(N) sum(1)∼sum(N) 的乘积。
输入
一个正整数 N N N。
输出
一个数,答案模 10000007 10000007 10000007 的值。
样例输入
3
样例输出
2
数据范围
对于 100 % 100\% 100% 的数据, N ≤ 1 0 15 N≤10^{15} N≤1015
思路
这道题是数位 d p dp dp,但是我用的是组合数。
我们从大到小枚举位数,找到是 1 1 1的位数,那我们就可以让它为 0 0 0,后面的位数就可以随便枚举了。接着枚举玩这一位之后,我们只要让它一直是 1 1 1,那么我们就可以继续枚举下面的,而不会重复也不会超上限来。
除了枚举位数(设用
i
i
i枚举),还要枚举未确定的位数中
1
1
1的个数(设用
j
j
j枚举),那么我们设之前以及确定来的是
1
1
1的位数的数量是
t
t
t,那么答案要乘上的值就是
(
t
+
j
)
C
i
j
(t+j)^{C^j_i}
(t+j)Cij。
(
t
+
j
)
(t+j)
(t+j)就是整个数列中
1
1
1的个数,而
C
i
j
C^j_i
Cij就不用说了,组合数嘛,求出
1
1
1的个数为
(
t
+
j
)
(t+j)
(t+j)的数有多少个嘛。
(至于
C
i
j
C^j_i
Cij怎么搞,肯定就是预处理啊,因为
n
n
n化为二进制肯定不超过
60
60
60位,那我们只需要预处理出
60
60
60内的就可以了)
最后输出的时候,有一点要注意,就是还要乘上计数器 t t t。因为按上面那样的话是不会算到 n n n本身的情况的,所以我们输出的时候还要再乘上 t t t才可以。
还有一个很重要的东西,因为
10000007
10000007
10000007它不是素数,所以我们预处理组合数的时候就不可以用
10000007
10000007
10000007,而是要用它的欧拉函数值。
φ
(
10000007
)
=
9988440
\varphi(10000007)=9988440
φ(10000007)=9988440
代码
#include<cstdio>
#define mo 10000007
#define ll long long
using namespace std;
ll n, C[61][61], t, ans = 1;
ll qsm(ll a, ll b) {//快速幂
ll anan = 1;
while (b) {
if (b & 1) anan = (anan * a) % mo;
a = (a * a) % mo;
b >>= 1;
}
return anan;
}
int main() {
for (int i = 0; i <= 60; i++)//预处理组合数
C[i][0] = 1;
for (int i = 1; i <= 60; i++)
for (int j = 1; j <= i; j++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % 9988440;//因为10000007不是素数,所以要用它的欧拉函数值phi(10000007)=9988440
scanf("%lld", &n);//读入
for (int i = 60; i >= 0; i--) {//枚举没确定位数
if (!((n >> i) & 1)) continue;//当前位是0
for (int j = 0; j <= i; j++)//枚举没确定的1的个数
if (t + j)//的出来的至少有一个1
ans = (ans * qsm(t + j, C[i][j])) % mo;//乘起来
t++;//加计数器
}
printf("%lld", ans * t % mo);//输出(要记得乘上计数器)
return 0;
}