[bzoj3209]花神的数论题_数位dp
花神的数论题 bzoj-3209
题目大意:sum(i)表示i的二进制表示中1的个数,求$\prod\limits_{i=1}^n sum(i)$
注释:$1\le n\le 10^{15}$。
想法:喷一下题目...神tm数论题,明明是个dp。
显然,如果稍微打个表的话就可以发现,有很多数的sum是相等的,我们不想重复乘这么多次,所以我们想到将所有sum相等的数弄到一起然后快速幂。这样,就不难想到数位dp
状态:dp[i][j]表示i位,sum值是j的个数。
转移是容易的,按照数位dp的边界特判就行了。
最后,附上丑陋的代码... ...
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long int ll; const int MAXN=60+5; const ll mod=10000007; ll n, Ans; ll C[MAXN][MAXN]; int l,wei[MAXN]; void pre() { for (int i=0;i<=60;++i) C[i][0]=1; for(int i=1;i<=60;i++) for(int j=1;j<=i;++j) C[i][j]=C[i-1][j-1]+C[i-1][j]; } ll Solve(int x) { ll sum=0; for(int i=l;i>=1;i--) { if(wei[i]==1) { sum+=C[i-1][x]; --x; } if(x<0) break; } return sum; } ll quick_power(ll x,ll y) { ll ans=1; while(y) { if(y&1) ans=(ans*x)%mod; y>>=1; x=(x*x)%mod; } return ans; } int main() { pre(); scanf("%lld",&n); ++n; l=0; while(n) { wei[++l]=n&1; n>>=1; } Ans=1ll; for(int i=1;i<=l;i++) { Ans=Ans*quick_power(i,Solve(i))%mod; } printf("%lld\n",Ans); return 0; }
小结:有意思...别被题面迷惑了(@EdwardFrog)
| 欢迎来原网站坐坐! >原文链接<