3209: 花神的数论题
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1893 Solved: 866
[Submit][Status][Discuss]
Description
背景
众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
描述
话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
花神的题目是这样的
设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你
派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。
Input
一个正整数 N。
Output
一个数,答案模 10000007 的值。
Sample Input
样例输入一
3
3
Sample Output
样例输出一
2
2
HINT
对于样例一,1*1*2=2;
数据范围与约定
对于 100% 的数据,N≤10^15
Source
花神系列出好题
显然应该枚举1的个数,计算有多少个小于等于N的数字,其中含有这么多的1。
这个显然就是数位DP了是吧,注意开个全局long long比较保险省心。
1 #include <cstdio> 2 3 #define int long long 4 5 const int siz = 65; 6 const int mod = 10000007; 7 8 inline int pow(int a, int b) 9 { 10 int ret = 1; 11 12 for (; b; b >>= 1) 13 { 14 if (b & 1) 15 { 16 ret *= a; 17 if (ret >= mod) 18 ret %= mod; 19 } 20 21 a *= a; 22 if (a >= mod) 23 a %= mod; 24 } 25 26 return ret; 27 } 28 29 int n; 30 int len; 31 int ans = 1; 32 int f[siz][siz]; 33 34 inline int count(int t) 35 { 36 int ret = 0; 37 38 for (int i = len - 1; ~i && ~t; --i) 39 if ((n >> i) & 1)ret += f[i][t--]; 40 41 return ret; 42 } 43 44 signed main(void) 45 { 46 scanf("%lld", &n); ++n; 47 48 for (int i = 0; i < siz; ++i) 49 f[i][0] = 1; 50 51 for (int i = 1; i < siz; ++i) 52 for (int j = 1; j <= i; ++j) 53 f[i][j] = f[i - 1][j] + f[i - 1][j - 1]; 54 55 while (n >> len)++len; 56 57 for (int i = 2; i <= len; ++i) 58 (ans *= pow(i, count(i))) %= mod; 59 60 printf("%lld ", ans); 61 }
@Author: YouSiki