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 }
(这上面表示的是有二进制中有$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: 花神的数论题的主要内容,如果未能解决你的问题,请参考以下文章