卧薪尝胆,厚积薄发。
花神的数论题
Date: Sat May 26 21:19:18 CST 2018
In Category:
NoCategory
Description:
设
$sum_i$
表示
$i$
的二进制表示中
$1$
的个数。给出一个正整数
$N$
,求
$\prod_{i=1}^{N} Sum_i$
$1 \le N \le 10^{15}$
Solution:
数位
$DP$
,设
$c[i][j]$
表示
$i$
为中有
$j$
个
$1$
的数的个数,
$c[i][j]=c[i-1][j-1]+c[i-1][j]$
,分别代表最后一位放不放
$1$
,在
$DP$
时枚举每一位,再枚举对于这一位所包含的区间(
$···100···00$
~
$···111···11$
)有多少个一,则落在这个区间内的
$1$
就有
$j-cnt$
个,
$cnt$
是他之上的
$1$
的位数,所以需要从高位向低位枚举,注意由于是乘,所以
$c[][]$
是指数,根据欧拉定理应该模
$\varphi(P)$
,注意由于统计的区间是
$(1 << (i - 1))$
~
$(1 << i) - 1$
,所以在刚开始要加
$1$
。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define MOD 10000007
#define PHI 9988440
typedef long long ll;
ll n;
ll c[64][64];
ll f[64];
ll power(ll a,ll b)
{
ll res = 1;
while(b > 0)
{
if(b & 1)res = (res * a) % MOD;
a = (a * a) % MOD;
b = b >> 1;
}
return res;
}
int main()
{
cin >> n;
++n;
for(int i = 0;i <= 63;++i)c[i][0] = c[i][i] = 1;
for(int i = 1;i <= 63;++i)for(int j = 1;j <= i;++j)c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % PHI;
memset(f,0,sizeof(f));
ll ans = 1;int cnt = 0;
for(int i = 63;i >= 0;--i)
{
if(n & (1ll << i))
{
for(int b = cnt;b <= 63;++b)
{
f[b] = (f[b] + c[i][b - cnt]) % PHI;
}
++cnt;
}
}
for(int i = 1;i <= 63;++i)ans = (ans * power(i,f[i])) % MOD;
cout << ans << endl;
return 0;
}
In tag:
DP-数位DP
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡