BZOJ3209: 花神的数论题
重在建模QwQ,要将题意转化为
枚举1的个数k,计算有多少个数含有k个1,(因为数位dp就是来做,有多少满足的数,且不关注数的大小)
最后加个快速幂就好
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; ll ans[70],n,dp[70][70][70]; ll num[70]; const ll mod=10000007; inline ll dfs(int pos,int now,int goal,bool limit) { if(pos==0&&now==goal) return 1; if(pos==0) return 0; if(!limit&&dp[pos][now][goal]!=-1) return dp[pos][now][goal]; int up=1; ll tot=0; if(limit) up=num[pos]; for(register int i=0;i<=up;++i) { if(i==1) tot+=dfs(pos-1,now+1,goal,limit&&(i==num[pos])); else tot+=dfs(pos-1,now,goal,limit&&(i==num[pos])); } if(!limit) dp[pos][now][goal]=tot; return tot; } inline ll quick_pow(ll x,ll y) { if(y==0) return 1; if(y==1) return x%mod; if(y%2==0) { ll tmp=quick_pow(x,y/2)%mod; return tmp*tmp%mod; } if(y%2!=0) { ll tmp=quick_pow(x,y/2)%mod; return x%mod*tmp*tmp%mod; } } inline ll solve(ll k) { int pos=0; while(k>0) { num[++pos]=k&1; k=k>>1; } for(register int i=1;i<=60;++i) ans[i]=dfs(pos,0,i,true); ll res=1; for(register int i=2;i<=60;++i) res=(res*quick_pow(i,ans[i]))%mod; return res; } int main() { scanf("%lld",&n); memset(dp,-1,sizeof(dp)); printf("%lld\n",solve(n)); return 0; }