[BZOJ3209]花神的数论题(数位dp)
2018-03-01 21:24
375 查看
传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=3209
之前用这位dalao的blog学的数位dp,模版也出自他,他讲的很不错!感谢他!!
一眼数位dp,想起来之前学了又放下没做的数位dp,于是就做了一下。
原问题为,1~N的数中每个数的1的个数的乘积
一开始想有什么玄学的数学做法,后来一想!
我们只要把问题转化为:枚举有k个1(因为最高才60个1),通过数位dp计算有多少个数含有k个1,最后用快速幂将结果累加即可
code:
之前用这位dalao的blog学的数位dp,模版也出自他,他讲的很不错!感谢他!!
一眼数位dp,想起来之前学了又放下没做的数位dp,于是就做了一下。
原问题为,1~N的数中每个数的1的个数的乘积
一开始想有什么玄学的数学做法,后来一想!
我们只要把问题转化为:枚举有k个1(因为最高才60个1),通过数位dp计算有多少个数含有k个1,最后用快速幂将结果累加即可
code:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int mod=10000007; ll n; ll dp[60][60];//dp[i][k]表示 最高位为i位,里面有k个1,这样的数的个数 int a[60]; ll pow_mod(ll a,ll b) { ll ans=1; while(b) { if (b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } ll dfs(int i,int k,bool limit) { if(k>i) return 0; if(i==0 && k==0) return 1; if(i==0) return 0; if(!limit && dp[i][k]!=-1) return dp[i][k]; int up=limit?a[i]:1; ll ans=0; for (int j=0;j<=up;j++) { if(j==0) ans+=dfs(i-1,k, limit&&j==a[i]); if(j==1) ans+=dfs(i-1,k-1,limit&&j==a[i]); } if(!limit) dp[i][k]=ans; return ans; } int main() { scanf("%lld",&n); memset(dp,-1,sizeof(dp)); int len=0; while(n) { a[++len]=n&1; n>>=1; } ll ans=1,k; for(int i=1;i<=len;i++)//枚举k的个数 { k=dfs(len,i,true); if(k) ans=ans*pow_mod(i,k)%mod; } printf("%lld",ans); return 0; }
相关文章推荐
- BZOJ3209 花神的数论题(数位dp)
- BZOJ 3209: 花神的数论题 [数位DP]
- BZOJ 3209: 花神的数论题 数位DP
- [数位dp] bzoj 3209 花神的数论题
- 【BZOJ3209】花神的数论题 数位DP(我姿势不标准,但是可能更好写)
- BZOJ3209:花神的数论题(数位dp)
- bzoj3209: 花神的数论题(数位Dp)
- bzoj 3209: 花神的数论题 数位dp
- bzoj 3209: 花神的数论题 数位dp
- 【BZOJ3209】花神的数论题 数位DP
- BZOJ 3209: 花神的数论题【数位dp】
- BZOJ_3209_花神的数论题_组合数+数位DP
- [Bzoj3209]花神的数论题(数位dp)
- [数位dp] bzoj 3209 花神的数论题
- [数位DP] BZOJ 3209 花神的数论题
- bzoj 3209 花神的数论题(数位dp)
- bzoj 3209: 花神的数论题【数位dp】
- bzoj3209 花神的数论题 数位DP
- 【bzoj3209】花神的数论题 数位DP
- BZOJ 3209 花神的数论题 数位dp