bzoj3209:3209: 花神的数论题
觉得还是数位dp的那种解题形式但是没有认真的想,一下子就看题解。其实还是设置状态转移。一定要多思考啊
f[i][j]=f[i-1][j]+g[i-1][j] g[i][j]=f[i-1][j-1]+g[i-1][j];
然后我就开始gang。然后先是for for j没有从0开始。然后是cnt增加的时候忘了*,接着是1<<tmp没有用ll,还有是读入优化没有用longlong,最后成功的过了若干较小的数据。WAWAWAWAWA5发。最后发现指数不能直接取模!。终于AC了喜极而泣TAT
=>关键是前两个错误思考了好久输出调试了好久渐渐的才知道自己哪里写错了。妈呀以后一遇到数位dp就把过程什么的全都输出一下。。。有关的东西打表出来确认每一步都没有错。。。
=>不过用了两个小时调试收获还是很大的。
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define clr(x,c) memset(x,c,sizeof(x)) #define ll long long ll read(){ //注意读入不要忘了longlong ll x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int mod=1e7+7; const int nmax=65; ll f[nmax][nmax],g[nmax][nmax]; ll pw(ll a,ll b){ ll ans=1; while(b){ if(b&1) ans=ans*a%mod; b>>=1;a=a*a%mod; } return ans; } ll cal(ll x){//10011 ll tmp,temp,cnt=0,ans=1; for(tmp=0;(1ll<<tmp)<=x;++tmp);//如果直接1<<tmp会爆 dwn(i,tmp,1){ temp=1ll<<(i-1); if(x&temp) { rep(j,1,i-1) ans=ans*pw(j+cnt,f[i][j])%mod; if(cnt) ans=ans*cnt%mod;++cnt; } } return ans*cnt%mod; } int main(){ ll n=read(); f[1][0]=g[1][1]=1; rep(i,2,60) rep(j,0,i){//指数不能直接取模!!! f[i][j]=f[i-1][j]+g[i-1][j]; if(j) g[i][j]=f[i-1][j-1]+g[i-1][j-1]; } printf("%lld\n",cal(n)); return 0; }
3209: 花神的数论题
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1802 Solved: 822
[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
3
Sample Output
样例输出一
2
2
HINT
对于样例一,1*1*2=2;
数据范围与约定
对于 100% 的数据,N≤10^15