SCOI2014 方伯伯的商場之旅

2022-03-31 17:17:57 字數 2173 閱讀 4982

題目描述

方伯伯有一天去參加乙個商場舉辦的遊戲。商場派了一些工作人員排成一行。每個人面前有幾堆石子。說來也巧,位置在 \(i\) 的人面前的第 \(j\) 堆的石子的數量,剛好是 \(i\) 寫成 \(k\) 進製後的第 \(j\) 位。

現在方伯伯要玩乙個遊戲,商場會給方伯伯兩個整數 \(l,r\)。方伯伯要把位置在 \([l, r]\) 中的每個人的石子都合併成一堆石子。每次操作,他可以選擇乙個人面前的兩堆石子,將其中的一堆中的某些石子移動到另一堆,代價是移動的石子數量\(\times\)移動的距離。商場承諾,方伯伯只要完成任務,就給他一些椰子,代價越小,給他的椰子越多。所以方伯伯很著急,想請你告訴他最少的代價是多少。

\(1≤l≤r≤10^, 2≤k≤20\)。

首先考慮一下對於某乙個數如何求出其合併成一堆的代價,觀察發現,最終答案的形態一定可以轉化成所有數字都移到某一位

那麼問題就轉化為找出乙個數字,使得其他數字移動到它的總代價最小,可以直接帶權中位數求解

但實際上,帶權中位數在數字 \(dp\) 的過程中狀態不好表示,不妨再多考慮一下子問題解法的由來

考慮一下帶權中位數 \(p\) ,其必然滿足 \(val_p + \sum_^ val_i \geq \sum_^\) ,反之同理,也就說,其無論往左移動或者往右移動都不會更優了

我們不妨先假設初始的 \(p = 1\) ,那麼就只需要考慮 \(p\) 往右移動到 \(p+1\) 新增的代價了,顯然是 \(\sum_^ val_i - \sum_^ val_i\)

此時如果代價 \(< 0\) 那麼說明往右移動會更優,當某一時刻代價 \(\geq 0\) 的時候說明 \(p\) 既不能往右移動也不能往左移動了,此時其是帶權中位數

也就是說,我們可以讓所有數先移動到 \(1\) ,然後算出每乙個 \(p\) 向右移動到 \(p+1\) 的代價,然後把所有 \(<0\) 的代價加上即可

具體實現的話就是乙個比較簡單的數字 \(dp\) ,考慮分兩步計算:

\(f[i][0/1]\) 表示前 \(i\) 個數字,之前是否是上界的字首的數全部移到第一位的總代價,列舉數字轉移即可

對於每乙個 \(p\in[1,len]\) ,算出 \(g[i][sum][0/1]\) 表示前 \(i\) 個數字,滿足 \(\sum_^ val_i - \sum_^ val_i = sum\) 的數的個數,也是簡單的列舉數字轉移即可

注意在前導 \(0\) 的處理上,前導 \(0\) 不能被計算到距離裡面,可以考慮每次只做恰好等於 \(n\) 位的數,多拿幾個上界做幾次,也可以加細節判掉,總複雜度是 \(o(log^3nk)\)

/*program by mangoyang*/

#include#define inf (0x7f7f7f7f)

#define max(a, b) ((a) > (b) ? (a) : (b))

#define min(a, b) ((a) < (b) ? (a) : (b))

typedef long long ll;

typedef unsigned long long ull;

using namespace std;

template inline void read(t &x)

#define int ll

const int zzd = 401;

int f[25][2], ss[25][2], g[25][1005][2], s[25], tmp[25], l, r, bs, lim, ans, ans2;

inline int getcost()

for(int j = 0; j < s[i]; j++)

f[i][1] += f[i-1][1];

ss[i][1] += ss[i-1][1] + f[i-1][1] * s[i] * (i - 1);

}res += ss[lim][0] + ss[lim][1];

return res;

}inline int solve(int num)

for(int j = 1; j <= 400; j++) cost -= (g[lim][j+zzd][0] + g[lim][j+zzd][1]) * j;

}return cost;

}inline int calc(int x)

signed main()

SCOI2014 方伯伯的商場之旅

方伯伯有一天去參加乙個商場舉辦的遊戲。商場派了一些工作人員排成一行。每個人面前有幾堆石子。說來也巧,位置在 i 的人面前的第 j 堆的石子的數量,剛好是 i 寫成 k 進製後的第 j 位。現在方伯伯要玩乙個遊戲,商場會給方伯伯兩個整數 l,r。方伯伯要把位置在 l,r 中的每個人的石子都合併成一堆石...

方伯伯的商場之旅 SCOI2014

方伯伯有一天去參加乙個商場舉辦的遊戲。商場派了一些工作人員排成一行。每個人面前有幾堆石子。說來也巧,位置在 i 的人面前的第 j 堆的石子的數量,剛好是 i 寫成 k 進製後的第 j 位。現在方伯伯要玩乙個遊戲,商場會給方伯伯兩個整數 l,r 方伯伯要把位置在 l,r 中的每個人的石子都合併成一堆石...

SCOI2014 方伯伯的商場之旅 解題報告

我一開始的想法會被兩個相同的集合位置去重給搞死,不過應該還是可以寫的,討論起來老麻煩。可以先欽定在 1 號點集合,然後往後調整一部分。具體一點,通過字首和減去字尾和的正負性移動 寫的時候把 sum 壓進去搞會非常簡單 code include include define ll long long ...