1. 程式人生 > >bzoj3598 [Scoi2014]方伯伯的商場之旅

bzoj3598 [Scoi2014]方伯伯的商場之旅

tput 記憶化 位統計 進制數 分隔 bsp amp res namespace

Description

方伯伯有一天去參加一個商場舉辦的遊戲。商場派了一些工作人員排成一行。每個人面前有幾堆石子。說來也巧,位置在 i 的人面前的第 j 堆的石子的數量,剛好是 i 寫成 K 進制後的第 j 位。 現在方伯伯要玩一個遊戲,商場會給方伯伯兩個整數 L,R。方伯伯要把位置在 [L, R] 中的每個人的石子都合並成一堆石子。每次操作,他可以選擇一個人面前的兩堆石子,將其中的一堆中的某些石子移動到另一堆,代價是移動的石子數量 * 移動的距離。商場承諾,方伯伯只要完成任務,就給他一些椰子,代價越小,給他的椰子越多。所以方伯伯很著急,想請你告訴他最少的代價是多少。 例如:10 進制下的位置在 12312 的人,合並石子的最少代價為: 1 * 2 + 2 * 1 + 3 * 0 + 1 * 1 + 2 * 2 = 9 即把所有的石子都合並在第三堆

Input

輸入僅有 1 行,包含 3 個用空格分隔的整數 L,R,K,表示商場給方伯伯的 2 個整數,以及進制數

Output

輸出僅有 1 行,包含 1 個整數,表示最少的代價。

Sample Input

3 8 3

Sample Output

5

HINT

1 < = L < = R < = 10^15, 2 < = K < = 20

正解:數位$dp$。

數位$dp$基本套路,拆成$[1,l-1]$和$[1,r]$,還有從高位到低位統計貢獻。

我們先把所有數都移到第一位的答案統計出來,那麽我們只要考慮哪些數需要往高位移。

我們把一個數從第$i-1$位移到第$i$位時候,可以發現,前$i-1$位數字距離$+1$,後面的數字距離$-1$,實際上就是前綴加一次,後綴減一次。

我們考慮每次往後移一位的貢獻差,如果這個貢獻差大於$0$,那就不用移了,因為這個貢獻差其實是一個單峰函數。

那麽我們可以先把全放到第一位的貢獻算出來,設$f[i][j]$表示前$i$位,$[i+1,n]$位貢獻和為$j$的總貢獻,可以用數位$dp$搞出來。

然後每次算出貢獻差並累加到答案中,狀態與上面是一樣的,只是轉移略有不同。

建議使用記憶化搜索實現,比較好寫。

 1 #include <bits/stdc++.h>
 2
#define il inline 3 #define RG register 4 #define ll long long 5 6 using namespace std; 7 8 ll f[55][3000],l,r; 9 int st[55],n,k; 10 11 il ll dfs(RG int pos,RG ll s,RG int lim){ 12 if (!pos) return s; 13 if (!lim && f[pos][s]!=-1) return f[pos][s]; 14 RG int end=lim ? st[pos] : k-1; RG ll res=0; 15 for (RG int i=0;i<=end;++i) 16 res+=dfs(pos-1,s+i*(pos-1),lim && i==end); 17 if (!lim) f[pos][s]=res; return res; 18 } 19 20 il ll dfs(RG int pos,RG ll s,RG int m,RG int lim){ 21 if (s<0) return 0; if (!pos) return s; 22 if (!lim && f[pos][s]!=-1) return f[pos][s]; 23 RG int end=lim ? st[pos] : k-1; RG ll res=0; 24 for (RG int i=0;i<=end;++i) 25 if (pos>=m) res+=dfs(pos-1,s+i,m,lim && i==end); 26 else res+=dfs(pos-1,s-i,m,lim && i==end); 27 if (!lim) f[pos][s]=res; return res; 28 } 29 30 il ll solve(RG ll x){ 31 RG ll ans; n=0; while (x) st[++n]=x%k,x/=k; 32 memset(f,-1,sizeof(f)),ans=dfs(n,0,1); 33 for (RG int i=2;i<=n;++i) 34 memset(f,-1,sizeof(f)),ans-=dfs(n,0,i,1); 35 return ans; 36 } 37 38 int main(){ 39 #ifndef ONLINE_JUDGE 40 freopen("shop.in","r",stdin); 41 freopen("shop.out","w",stdout); 42 #endif 43 cin>>l>>r>>k; 44 cout<<solve(r)-solve(l-1); 45 return 0; 46 }

bzoj3598 [Scoi2014]方伯伯的商場之旅