bzoj3209-花神的數論題
阿新 • • 發佈:2019-01-07
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
對於樣例一,112=2;
資料範圍與約定
對於 100% 的資料,N≤10^15.
Solution
簡單的數位dp.
列舉1的個數, 然後dp求出數的個數.
注意指數不能取模!
由於指數意義是數的個數, 顯然不會超過long long, 直接快速冪即可.
Code
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> using namespace std; #define rep(i,l,r) for(register int i=(l);i<=(r);++i) #define repdo(i,l,r) for(register int i=(l);i>=(r);--i) #define il inline typedef double db; typedef long long ll; //--------------------------------------- const ll nsz=60,nmod=1e7+7; ll n; ll dig[nsz],pd=0; ll dp[nsz][nsz]; ll qp(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%nmod; a=a*a%nmod,b>>=1; } return res; } ll sol1(ll cnt){ ll res=0; repdo(i,pd,1){ if(dig[i])res=res+dp[i-1][cnt],--cnt; if(cnt<0)break; } if(cnt==0)++res; return res; } ll sol(){ while(n)dig[++pd]=n&1,n>>=1; rep(i,0,pd)dp[i][0]=1; rep(i,1,pd)rep(j,1,i)dp[i][j]=dp[i-1][j]+dp[i-1][j-1]; // rep(i,0,pd){rep(j,0,pd)cout<<dp[i][j]<<' ';cout<<'\n';} ll ans=1; rep(i,1,pd){ ans=(ans*qp(i,sol1(i)))%nmod; } return ans; } int main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n; cout<<sol()<<'\n'; return 0; }