BZOJ3209: 花神的数论题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3209: 花神的数论题相关的知识,希望对你有一定的参考价值。

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3209


 

显然是按照二进制位进行DP。

考虑预处理$F[i][j]$表示到了二进制的第$i$位,有$j$个$1$的数字有多少个。

显然:${F[i][j]=F[i-1][j-1]+F[i-1][j]}$

组合数。。。

接下来只需补充不漏的计算比$n+1$小的每一个数字对应的1的多少。数位统计即可。

技术分享
 1 llg work(llg x)
 2 {
 3     llg tot=0;
 4     for (llg i=tail;i>=1;i--)
 5     {
 6         if (x<0) break;
 7         if (a[i])
 8         {
 9             tot+=c[i-1][x];
10               x--;
11         }
12     }
13     return tot;
14 }
View Code

(这上面表示的是有二进制中有$x$个$1$的数有多少个)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 using namespace std;
 9 #define maxn 10010
10 #define md 10000007
11 #define llg long long 
12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
13 llg n,m,a[maxn],c[100][100],tail,ans;
14 
15 llg ksm(llg A,llg B)
16 {
17     llg ans=1;
18     while (B)
19     {
20         if (B%2) ans*=A,ans%=md;
21         A*=A; A%=md;
22         B/=2;
23     }
24     return ans;
25 }
26 
27 llg work(llg x)
28 {
29     llg tot=0;
30     for (llg i=tail;i>=1;i--)
31     {
32         if (x<0) break;
33         if (a[i])
34         {
35             tot+=c[i-1][x];
36               x--;
37         }
38     }
39     return tot;
40 }
41 
42 int main()
43 {
44     yyj("bzoj3209");
45     cin>>n;
46     n++;
47     for (llg i=0;i<=60;i++) c[i][0]=1;
48     for (llg i=1;i<=60;i++)
49         for (llg j=1;j<=i;j++)
50             c[i][j]=c[i-1][j]+c[i-1][j-1];
51     while (n!=0)
52     {
53         a[++tail]=n%2;
54         n/=2;
55     }
56     ans=1;
57     for (llg i=1;i<=60;i++) 
58         ans*=ksm(i,work(i)),ans%=md;
59     cout<<ans;
60     return 0;
61 }

 

以上是关于BZOJ3209: 花神的数论题的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3209花神的数论题 数位DP

bzoj 3209: 花神的数论题 数位dp

[BZOJ3209]花神的数论题 组合数+快速幂

bzoj3209 花神的数论题

bzoj3209 花神的数论题

BZOJ 3209 花神的数论题