洛谷 P4317 花神的數論題
阿新 • • 發佈:2021-08-05
洛谷 P4317 花神的數論題
數位dp
這道題我個人認為還是有一定思維難度的
題目要求輸出 \(ans = \prod\limits_{i=1}^nsum_i\),\(sum_i\) 為 \(i\) 在二進位制下 \(1\) 的個數
那我們換個角度考慮, \(ans = \prod\limits_{i=1}^{len}{i^{s_i}}\),\(len\) 為最多有多少個 \(1\) ,\(s_i\) 為二進位制下有 \(i\) 個 1 的數的個數。
思考一下二者是不是相等,想明白這個之後我們就可以愉快的切題啦
別忘了開 \(long\ long\)
附程式碼(有註釋)
#include <iostream> #include <cstdio> #include <cstring> #define mod 10000007 #define ll long long using namespace std; ll n, len; ll num[60], sum[60]; //注意不是十進位制,是二進位制數,所以要開大一些 ll dp[60][60][2]; ll power(ll a, ll b){ //快速冪板子 ll res = 1; while(b){ if(b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res % mod; } ll dfs(ll len, ll s, ll now, ll lim){ //s為1的個數,now為正在預處理的1的個數 if(!len) return s == now; if(dp[len][s][lim] != -1) return dp[len][s][lim]; ll res = lim ? num[len] : 1; //注意是1,而不是9,啊啊啊我當時這裡卡了好久 ll ans = 0; for(ll i = 0; i <= res; i++) ans += dfs(len - 1, s + i, now, lim && (i == res)); return dp[len][s][lim] = ans; } ll solve(ll x){ len = 0; while(x){ num[++len] = x % 2; //這裡也是%2 /2 x /= 2; } for(ll i = 1; i <= len; i++){ memset(dp, -1, sizeof(dp)); sum[i] += dfs(len, 0, i, 1); //sum是上文的s } ll ans = 1; for(ll i = 1; i <= len; i++) ans = ans * power(i, sum[i]) % mod; return ans; } signed main(){ scanf("%lld", &n); printf("%lld\n", solve(n)); return 0; }
完結撒花~