BZOJ 3209: 花神的數論題 (數位dp)
阿新 • • 發佈:2018-08-27
來講 span fine turn 一次 ans std 描述 return
題目描述
背景
眾所周知,花神多年來憑借無邊的神力狂虐各大 OJ、OI、CF、TC …… 當然也包括 CH 啦。
描述
話說花神這天又來講課了。課後照例有超級難的神題啦…… 我等蒟蒻又遭殃了。
花神的題目是這樣的
設 sum(i) 表示 i 的二進制表示中 1 的個數。給出一個正整數 N ,花神要問你
派(Sum(i)),也就是 sum(1)—sum(N) 的乘積。
輸入
一個正整數 N。
輸出
一個數,答案模 10000007 的值。
樣例輸入
樣例輸入
3
樣例輸出
樣例輸出
2
對於 100% 的數據,N≤10^15
題解
數位dp,抄的大佬的題解
然而實在不是很看得懂……
下面$g[i]$表示$1$恰好有$i$個時候的方案數
然後為啥能這樣轉移呢?我想了想,大概是因為它每一次遇到$1$時,就默認這一位可以放,那麽每一個$g[i]$都能轉移到$g[i+1]$,然後後面還有$1$那麽考慮後面的,這樣防止超出界限
1 //minamoto 2 #include<cstdio> 3 #define ll long long 4 const int mod=1e7+7; 5 ll ans=1,n,c,g[55]; 6 ll qpow(ll x,ll y){7 ll res=1; 8 while(y){ 9 if(y&1) res=res*x%mod; 10 y>>=1,x=x*x%mod; 11 } 12 return res; 13 } 14 int main(){ 15 scanf("%lld",&n); 16 for(int j=49;~j;--j){ 17 for(int i=49;i;--i) g[i]+=g[i-1]; 18 if(n>>j&1) ++g[c++];19 } 20 ++g[c]; 21 for(int i=1;i<=49;++i) ans=ans*qpow(i,g[i])%mod; 22 printf("%lld\n",ans); 23 return 0; 24 }
BZOJ 3209: 花神的數論題 (數位dp)