#数位dp#洛谷 4317 花神的数论题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/86681639

感谢dalao@小粉兔的帮助
dalao’s 博客园,dalao’s 洛谷博客

题目

f [ i ] f[i] 表示 i i 转化为二进制后1的个数,求 i = 1 n f [ i ] \prod_{i=1}^nf[i]


分析

很容易发现,这应该是一道数位dp的题目,但是怎么做呢,设 d p [ i ] dp[i] 表示数值小于 n n 的恰好有 k k 个二进制位为1的数的个数,那么这就和 n n 有关系了,如果 n n 的第 j j 位是1,那么说明第 j j 位可以拓展,那么 + + d p [ j ] ++dp[j] ,由于每一次算完之后只要在前面加上1就可以得到 d p [ j + 1 ] dp[j+1] ,那么 d p [ j + 1 ] + = d p [ j ] dp[j+1]+=dp[j] ,最后dp完之后那么停留的那一位还是可以加上去的,所以最后的代码,感谢小粉兔


代码

#include <cstdio>
#define rr register
using namespace std;
const int mod=10000007;
typedef long long ll;
ll dp[51],n,ans=1,now;
inline ll ksm(ll x,ll y){
	rr ll ans=1;
	for (;y;y>>=1,x=(x*x)%mod)
	    if (y&1) ans=(ans*x)%mod;
	return ans;
}
signed main(){
	scanf("%lld",&n);
	for (rr ll j=49;~j;--j){
		for (rr ll i=49;i;--i) dp[i]+=dp[i-1];
		if (n>>j&1) ++dp[now],++now;
	}
	++dp[now];
	for (rr ll i=1;i<50;++i) ans=ans*ksm(i,dp[i])%mod;
	printf("%lld",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/86681639