【做题】方伯伯的商场之旅——枚举决策

这道题的数位dp是很显然的。然而,本题不仅要计数还要保证最优化,这使得我们难以得到一个简单的dp状态表示方式。

遗憾的是考虑dp状态数的直接减少是一个错误的思考方向。本人在此浪费了几个小时的时间。

注意到虽然是最优化,但决策数是非常少的,仅有O(logn)级别。同时,我们可以很容易地判断一个解是不是最优的。

于是,我们可以枚举最终合并到哪一位,然后就很容易了,本人是维护满足这个条件的数的个数和答案的和,这里就不详细讲了。

最后一个问题在于一个数可能在多个位置都是决策最优的。注意到它的充要条件是选择的那一位(设值为x)左右两边sum的差为0或x,于是只要在判断时把闭区间改成半闭半开区间就可以了。

这数位和为sum,则时间复杂度为O(log2n*sum*k2)。

 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 }

 

小结:对于难维护的东西,可以通过添加额外信息来完成。

posted @ 2018-03-08 18:38  莫名其妙的aaa  阅读(129)  评论(0编辑  收藏  举报