也是一道不錯的數位DP,考慮先轉成二進制後再作ui
轉化一下問題,考慮統計出\([1,n]\)中在二進制下有\(i\)個\(1\)的方案數\(cnt_i\),那麼答案顯然就是\(\prod i^{cnt_i}\)spa
而後咱們仍是先預處理一個東西\(s_{i,j}\),表示在二進制下前\(i\)位中填上\(j\)個\(1\)的方案數,則有轉移:code
\(s_{i,j}=s_{i-1,j}+s_{i-1,j-1}(i>1)\),同時有\(s_{i,0}=1\)it
這轉移很簡單吧,就是考慮這一位填上\(0/1\)io
觀察一下發現其實這就是個楊輝三角,不過好像並無什麼用。class
接下來枚舉有\(i\)個\(1\)的狀況,那麼從高位填到低位,對於每一位上的\(1\),我後面怎麼填都是知足要求的二進制
所以此時的\(cnt_i+=s_{l,k}\),\(l\)表示後面還有多少位(比它低的位),\(k\)表示以前(包括如今)已經出現多少個\(1\),最後直接快速冪計算一下就行了。統計
注意到這樣只能處理小於\(n\)的數的狀況(通常不少二進制下的數位DP都有這個通病),因此咱們直接把\(n\)加一便可。di
CODEwhile
#include<cstdio> using namespace std; const long long N=65,mod=10000007; long long n,s[N][N],ans=1LL,cnt,bit[N]; inline void resolve(long long x) { while (x) bit[++cnt]=x&1,x>>=1; } inline long long solve(long long x) { register long long i; long long tot=0; for (i=cnt;i>=1&&~x;--i) if (bit[i]) tot+=s[i-1][x--]; return tot; } inline long long quick_pow(long long x,long long p) { long long tot=1; while (p) { if (p&1) tot=tot*x%mod; x=x*x%mod; p>>=1; } return tot; } int main() { register long long i,j; scanf("%lld",&n); resolve(++n); for (s[0][0]=1,i=1;i<=cnt;++i) for (j=0;j<=i;++j) s[i][j]=j?s[i-1][j]+s[i-1][j-1]:s[i-1][j]; for (i=1;i<=cnt;++i) ans=ans*quick_pow(i,solve(i))%mod; return printf("%lld",ans),0; }