斜率優化DP APIO2014 序列分割

2022-05-24 14:03:12 字數 2590 閱讀 5749

你正在玩乙個關於長度為 \(n\) 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 \(k + 1\) 個非空的塊。為了得到 \(k + 1\) 塊,你需要重複下面的操作 \(k\) 次:

選擇乙個有超過乙個元素的塊(初始時你只有一塊,即整個序列)

選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。

每次操作後你將獲得那兩個新產生的塊的元素和的乘積的分數。你想要最大化最後的總得分。

第一行包含兩個整數 \(n\) 和 \(k\)。保證 \(k + 1 \leq n\)。

第二行包含 \(n\) 個非負整數 \(a_1, a_2, \cdots, a_n\) (\(0 \leq a_i \leq 10^4\)),表示前文所述的序列。

第一行輸出你能獲得的最大總得分。

第二行輸出 \(k\) 個介於 \(1\) 到 \(n - 1\) 之間的整數,表示為了使得總得分最大,你每次操作中分開兩個塊的位置。第 \(i\) 個整數 \(s_i\) 表示第 \(i\) 次操作將在 \(s_i\) 和 \(s_\) 之間把塊分開。

如果有多種方案使得總得分最大,輸出任意一種方案即可。

第乙個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 10\)。

第二個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 50\)。

第三個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 200\)。

第四個子任務共 \(17\) 分,滿足 \(2 \leq n \leq 1000, 1 \leq k \leq \min\\)。

第五個子任務共 \(21\) 分,滿足 \(2 \leq n \leq 10000, 1 \leq k \leq \min\\)。

第六個子任務共 \(29\) 分,滿足 \(2 \leq n \leq 100000, 1 \leq k \leq \min\\)。

首先可以通過數學歸納法證明: 只要切割位置相同, 切割順序不會影響答案.

首先有乙個 \(拿衣服\) 的想法 直接想到正解的大佬可以跳過:

​ 用 \(i\) 表示當前的位置, \(k\) 表示切割的次數, 列舉之前的每乙個狀態 \(j\).

\[f\left(i, k\right) = \max\left\, j \in \left[1, i-1\right]

\]​ 但是由於它太 \(拿衣服\) 了, 所以不好處理(實際可做).

反向考慮整個序列, 轉移方程變形為:

\[f\left(i, k\right) = \max\left\, j \in \left[1, i-1\right]

\]看資料 \(1e6\), \(o\left(n^2k\right)\) 顯然不可做, 憑感覺考慮斜率優化

設 \(f\left(i, k\right) = f(i)\), $f\left(i, k-1\right) = g(i) $ , 進行移項, 有:

\[g\left(j\right) - s^2\left(j\right) = -s\left(i\right)s\left(j\right) + f\left(i\right)

\]​ 斜率 \(-s(i)\) 單調遞減.

考慮當前決策 \(j\) 和前乙個決策 \(j-1\), 若 \(j\) 優於 \(j-1\), 有:

\[k = \frac \gt -s(i)

\]即:

\[\frac \le s(i)

\]然後就可以大力斜率優化並wa掉

注意乙個細節: \(a_i\) 可能為 \(0\), 上式的分母可能為 \(0\), 需要在程式中特判一下.

**:

# include # include # include # define ll long long

# define maxn 1000005

using namespace std;

ll a[maxn], sum[maxn];

ll f[maxn][2];

int sol[maxn][205]; // 記錄轉移順序

int q[maxn];

double slope(int i,int j, int g)

int main()

for(int k = 0, lim = 1; lim <= s; k^=1, lim++)

f[i][k] = f[q[l]][g]+sum[q[l]]*(sum[i]-sum[q[l]]);

sol[i][lim] = q[l];

while(l < r && slope(q[r-1],q[r], g)>=slope(q[r],i, g))

q[++r] = i;

} }printf("%lld\n", max(f[n][1], f[n][0]));

for(int x=n,i=s;i>=1;--i)

return 0;

}

時間複雜度: \(o(nk)\)

玄學 \(1\): 最開始寫的deque的時候莫名其妙赤橙黃綠青藍紫, 改手寫單調佇列就過了 估計是我哪寫錯了

玄學 \(2\): 本來打算移項逃避精度問題的, 結果鍋掉 估計就是式子移錯了

APIO2014 序列分割 斜率優化DP

apio2014 序列分割 題目大意 你正在玩乙個關於長度為 n 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 k 1 個非空的塊。為了得到 k 1 塊,你需要重複下面的操作 k 次 選擇乙個有超過乙個元素的塊 初始時你只有一塊,即整個序列 選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。...

NOI2014 購票 樹上斜率優化

首先易得方程,且經過變換有 begin f i min limits f j p idist j f i dist ip i q i end 在一條直線上時,斜率優化可以用普通 cdq 分治實現 會不會過於麻煩?那麼對於在樹上斜率優化時,考慮點分治 這時就在點分治中運用 cdq 分治的思想,即使用在...

NOI2014 購票(樹形dp 樹剖 斜率優化)

考慮樹形 dp,設 dpi dp i dpi 為 ii i 節點到 sz 市的最小費用,dis idis i disi 為 sz 市到 i ii 節點的距離。顯然初始化 dp1 0 dp 1 0 dp1 0 然後 dis idis i disi 可以提前預處理出來。然後有 dpu min dpv d...