3209: 花神的数论题
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2633 Solved: 1182
[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
Source
然后我们发现不能一起转移,但我们可以求出<=N中 1的个数为k的所有数
最终答案就是
。

关于dfs那个转移,就是很裸的模板题,看代码即可。
AC代码:
# include <iostream> # include <cstdio> # include <cstring> using namespace std; typedef long long LL; const LL mod = 10000007; LL f[64][64],n;int data[64],len; LL dfs(int now,int num,bool lim,bool first) { if(num < 0)return 0; if(!now)return !num; if(!lim && !first && f[now][num] != -1)return f[now][num]; LL ret = 0;int p = lim ? data[now] : 1; for(int i = 0;i <= p;i++) ret += dfs(now - 1,num - i,lim && i == p,first && !i); if(!lim && !first)f[now][num] = ret; return ret; } LL cmd(LL k,LL x) { LL c = 1; while(k) { if(k & 1LL)c = c * x % mod; x = x * x % mod; k >>= 1LL; } return c; } LL calc(LL k) { memset(f,-1,sizeof f); len = 0; while(k)data[++len] = k % 2,k /= 2; LL ret = 1; for(int i = 1;i <= len;i++) ret = ret * cmd(dfs(len,i,true,true),i) % mod; return ret; } int main() { scanf("%lld",&n); printf("%lld\n",calc(n)); }