BZOJ 3209: 花神的数论题

3209: 花神的数论题

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

样例输出一

2

HINT

 



对于样例一,1*1*2=2;


数据范围与约定


对于 100% 的数据,N≤10^15

 

Source

[Submit][Status][Discuss]

 

花神系列出好题

显然应该枚举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\n", ans);
61 }

 

@Author: YouSiki

 

posted @ 2017-01-18 19:46  YouSiki  阅读(179)  评论(0编辑  收藏  举报