zoukankan      html  css  js  c++  java
  • 【BZOJ3209】花神的数论题 数位DP

    【BZOJ3209】花神的数论题

    Description

    背景
    众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
    描述
    话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
    花神的题目是这样的
    设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你
    派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。

    Input

    一个正整数 N。

    Output

    一个数,答案模 10000007 的值。

    Sample Input

    样例输入一

    3

    Sample Output

    样例输出一

    2

    HINT

    对于样例一,1*1*2=2;

    数据范围与约定

    对于 100% 的数据,N≤10^15

    题解:又一个题目名称和题本身一点关系都没有的~

    很容易想到按位拆分,分别考虑1的个数是k的数有多少个,然后快速幂一下计算贡献

    怎么知道1的个数是k的数有多少个呢?预处理出组合数,然后数位DP吧!(对本蒟蒻来说就是INF的细节)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const ll mod=10000007;
    ll c[60][60];
    ll cnt[60];
    ll n,sum,ans;
    ll pm(ll x,ll y)
    {
    	ll z=1;
    	while(y)
    	{
    		if(y&1)	z=z*x%mod;
    		x=x*x%mod,y>>=1;
    	}
    	return z;
    }
    int main()
    {
    	c[0][0]=1;
    	ll i,j;
    	for(i=1;i<=50;i++)
    	{
    		c[i][0]=1;
    		for(j=1;j<=i;j++)	c[i][j]=c[i-1][j-1]+c[i-1][j];
    	}
    	scanf("%lld",&n);
    	for(i=50;i;i--)
    	{
    		if(n&(1ll<<i-1))
    		{
    			for(j=sum;j<=50;j++)	cnt[j]+=c[i-1][j-sum];
    			sum++;
    		}
    	}
    	cnt[sum]++;
    	for(ans=i=1;i<=50;i++)	ans=ans*pm(i,cnt[i])%mod;
    	printf("%lld",ans);
    	return 0;
    }
  • 相关阅读:
    云计算openstack核心组件——neutron网络服务(9)
    云计算openstack核心组件——neutron网络服务(8)
    flexible.js 布局详解
    libflexible源码阅读
    H5适配方案
    微信分享朋友圈示例代码
    微信接口示例代码
    微信JSSDK上传图片,代码为上传单张图
    H5动画开发快车道
    Centos 6.5 安装 Nginx+MySQL+PHP
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7044287.html
Copyright © 2011-2022 走看看