码迷,mamicode.com
首页 > 其他好文 > 详细

HYSBZ 3209: 花神的数论题

时间:2015-07-24 23:52:19      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

题目连接:http://www.lydsy.com/JudgeOnline/problem.php?id=3209

 

花神的数论题

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1148  Solved: 535
[Submit][Status][Discuss]

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到n每个数的sum值的乘积,sum表示其二进制中1的个数,比如5的二进制是101,有2个1,所以sum(5)=2;
思路:n很大,不可能把每一个sum(i)都算出来,但是仔细想想sum是表示二进制的个数,n在64位long long范围内,sum不可能大于64,这说明
有很多sum(i)的值是一样的,比如1010、1100、1001.....这些不同数的二进制的sum值都为2。这样就可以用cnt[k]表示有k个1的二进制数的个数
(0<=k<64)(其实达不到64),题目要算乘积那就是cnt[k]个k相乘即kcnt[k](这个用快速幂算),然后枚举k去算cnt[k],数位dp嘛,我用的是记忆化搜索
写的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
const int INF=0x3f3f3f3f;
const int mod=10000007;
typedef long long ll;
int a[100];
ll dp[65][65][65];
ll Pow(int a,ll n)//快速幂
{
    ll ans=1,tmp=(ll)a;
    while(n)
    {
        if(n&1)
            ans=(ans%mod)*(tmp%mod)%mod;
        tmp=(tmp%mod)*(tmp%mod)%mod;
        n>>=1;
    }
    return ans%mod;
}
ll dfs(int pos,int now,int all,int limit)
//pos是当前数位,now是已经选择的数位的和,all是所需的总和,
//limit是限制前一位有没有达到上限。
{
    if(pos==0)
        return now==all;
    if(limit==0 && dp[pos][now][all]!=-1) return dp[pos][now][all];
    int upper=limit?a[pos]:1;
    ll tmp=0;
    for(int i=0;i<=upper;i++)//数位只有0,1;
    {
        tmp+=dfs(pos-1,now+i,all,limit && i==a[pos]);
    }
    if(limit==0) dp[pos][now][all]=tmp;//记忆化
    return tmp;
}

ll solve(ll n)
{
    int pos=0;
    ll ans=1,cnt;
    while(n)
    {
        a[++pos]=n%2;
        n/=2;
    }
    memset(dp,-1,sizeof dp);
    for(int i=1;i<=pos;i++)
    {
        cnt=dfs(pos,0,i,1);
        ans=(ans%mod*Pow(i,cnt))%mod;
    }
    return ans%mod;
}
int main()
{
    ll n;
    while(~scanf("%lld",&n))
    {
   
        printf("%lld\n",solve(n));
    }
    return 0;
}

  

 

HYSBZ 3209: 花神的数论题

标签:

原文地址:http://www.cnblogs.com/2445512490wh/p/4674931.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!