1. 程式人生 > >【做題】方伯伯的商場之旅——枚舉決策

【做題】方伯伯的商場之旅——枚舉決策

得到 pre 決策 lld 添加 sum c++ 方向 可能

這道題的數位dp是很顯然的。然而,本題不僅要計數還要保證最優化,這使得我們難以得到一個簡單的dp狀態表示方式。

遺憾的是考慮dp狀態數的直接減少是一個錯誤的思考方向。本人在此浪費了幾個小時的時間。

註意到雖然是最優化,但決策數是非常少的,僅有O(logn)級別。同時,我們可以很容易地判斷一個解是不是最優的。

於是,我們可以枚舉最終合並到哪一位,然後就很容易了,本人是維護滿足這個條件的數的個數和答案的和,這裏就不詳細講了。

最後一個問題在於一個數可能在多個位置都是決策最優的。註意到它的充要條件是選擇的那一位(設值為x)左右兩邊sum的差為0或x,於是只要在判斷時把閉區間改成半閉半開區間就可以了。

這數位和為sum,則時間復雜度為O(log2n*sum*k)。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef pair<ll,ll> pll;
 5 const int N = 55, SUM = 250, K = 25;
 6 ll dp[N][SUM][K],l,r,su[N][SUM][K];
 7 int num[N],cur,k,cnt;
 8 pll dfs(int pos,int sum,int val,bool
lim) { 9 if (pos == 0) return pll(sum <= 2 * val,0); 10 if ((!lim) && (~dp[pos][sum][val])) 11 return pll(dp[pos][sum][val],su[pos][sum][val]); 12 ll ta = 0, tb = 0; 13 pll tmp; 14 for (int i = 0 ; i <= (lim ? num[pos] : k-1) ; ++ i) { 15 if (pos < cur && sum - i <= 0
) break; 16 tmp = dfs(pos-1,pos < cur ? sum-i : sum+i,pos == cur ? i : val,lim && (i == num[pos])); 17 ta += tmp.first; 18 tb += tmp.second + tmp.first * abs(pos-cur) * i; 19 } 20 if (!lim) { 21 dp[pos][sum][val] = ta; 22 su[pos][sum][val] = tb; 23 } 24 return pll(ta,tb); 25 } 26 ll solve(ll x) { 27 ll res = 0; 28 cnt = 0; 29 while (x) num[++cnt] = x%k, x /= k; 30 for (cur = 1 ; cur <= cnt ; ++ cur) { 31 memset(dp,-1,sizeof dp); 32 memset(su,-1,sizeof su); 33 res += dfs(cnt,0,0,1).second; 34 } 35 return res; 36 } 37 int main() { 38 scanf("%lld%lld%d",&l,&r,&k); 39 printf("%lld\n",solve(r) - solve(l-1)); 40 return 0; 41 }

小結:對於難維護的東西,可以通過添加額外信息來完成。

【做題】方伯伯的商場之旅——枚舉決策