BZOJ 3209 花神的数论题 数位dp

来源:互联网 发布:samorost3 mac下载 编辑:程序博客网 时间:2024/06/05 02:29

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













传送门
一开始看成了sigma(sum(1)……sum(n)),结果就随手上了= =
原来是乘积……突然不会
好吧其实还行,只要把问题转化掉就好了,
10^15约莫2^50,所以最多50个1,
枚举1的个数x,问题变成求出1~n内每个数的二进制含1个数恰好为x的个数,
假设这个个数为y,那么对答案的贡献就是x^y
怎么求呢……数位dp吧= =直接二进制的数位dp

一开始没加快速幂而10^8 TLE了好久……
我还以为是记忆化错了呢= =气死





#include<bits/stdc++.h>#define ll long longusing namespace std;const ll    Mod=10000007;ll n,f[55][55];int len,a[55];ll dfs(int now,bool limit,int num){    if (num<0) return 0;    if (now>len) return num==0;    if (!limit && f[now][num]>=0) return f[now][num];    ll t=dfs(now+1,limit&(a[now]==0),num);    if (!limit || a[now]==1) t+=dfs(now+1,limit,num-1);    if (!limit) f[now][num]=t;    return t;}ll ksm(ll a,ll b){    ll ans=1LL;a%=Mod;    while (b){        if (b&1LL) ans=ans*a%Mod;        b>>=1LL;        a=a*a%Mod;    }    return ans;}int main(){    scanf("%lld",&n);    len=0;    while (n) a[++len]=n&1LL,n>>=1LL;    for (int i=1;i<=(len>>1);i++) swap(a[i],a[len-i+1]);    memset(f,255,sizeof(f));    ll ans=1LL;    for (int i=1;i<=len;i++){        ll t=ksm(i,dfs(1,1,i));        ans=ans*t%Mod;    }    printf("%lld\n",ans);    return 0;}

原创粉丝点击