題目描述你正在玩乙個關於長度為 n 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 k+1 個非空的塊。為了得到 k+1 塊,你需要重複下面的操作 k 次:
選擇乙個有超過乙個元素的塊(初始時你只有一塊,即整個序列)
選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。
每次操作後你將獲得那兩個新產生的塊的元素和的乘積的分數。你想要最大化最後的總得分。
輸入格式
第一行包含兩個整數 n 和 k。保證 k+1≤n。
第二行包含 n 個非負整數 a1,
a2,⋯
,a
na_1, a_2, \cdots, a_n
a1,a2
,⋯,
an(0≤
ai≤1
04
)(0≤ai≤10^4)
(0≤ai≤
104)
,表示前文所述的序列。
輸出格式
第一行輸出你能獲得的最大總得分。
第二行輸出 k 個介於 1 到 n - 1 之間的整數,表示為了使得總得分最大,你每次操作中分開兩個塊的位置。第 i 個整數 s
is_i
si 表示第 i 次操作將在 s
is_i
si 和 si+
1s_
si+1
之間把塊分開。
如果有多種方案使得總得分最大,輸出任意一種方案即可。
輸入輸出樣例輸入 #1
7 34 1 3 4 0 2 3
輸出 #11081 3 5
說明/提示2 ≤n
≤100000,1
≤k≤m
in
2≤n≤100000,1≤k≤min\
2≤n≤10
0000
,1≤k
≤min
解釋:dp[k][i
]:
dp[k][i]:
dp[k][
i]:在i出化第k刀的最大值,則dp[
k][i
]=ma
xdp[k][i]=max\
dp[k][
i]=m
ax我們列舉k,進行斜率優化就可以了,老套路
設j
>
kj>k
j>
k,且j
jj優於k
kk,則最後可以化得(dp
[j]−
dp[k
])/(
sum[
j]−s
um[k
])
>su
m[n]
−sum
[i
](dp[j]-dp[k])/(sum[j]-sum[k])>sum[n]-sum[i]
(dp[j]
−dp[
k])/
(sum
[j]−
sum[
k])>su
m[n]
−sum
[i],然後套斜率優化模板就好了。注意0要單獨處理掉,0不會對答案最貢獻,但可以出現斜率不存在的情況。
#include#include#define ll long long
#define n 100004
using namespace std;
int n=0,k=0;
ll sum[n]=;
int q[n]=;
ll dp[203][n]=;
int front[203][n]=;
int ans[203]=;
int temp[n]=;
int t=0;
double cal(int x,int y,int k)
int main()
}n=t;t=0;
for(int i=1;i<=k;i++)
P3648 APIO2014 序列分割
part1 首先看到題目,嗯 o o很騷 手玩一波樣例之後發現狀態很好想 這裡簡單地任務階段可以被劃分次數 也就是劃分順序 和劃分位置來劃分 初步想法是 f i j 表示前 i 次最後一次切的是 j 位置 隨後意識到沒法通過上一層進行轉移,這裡出現問題也是正常,因為沒有進行更深入地發掘性質 此處無法...
Luogu 3648 APIO2014 序列分割
題目鏈結 首先要發現乙個重要的性質 分割的順序是不會影響答案的 證明 首先對於沒有交的兩段區間,顯然先後順序改變不會有影響 而對於在同一段區間上的兩次分割 設有一段序列由長度為 x,y,z 的三段拼接起來 如果先分割 xy 和 z 再分割 x 和 y 答案是 x y z x y 而如果先分割 x 和...
P3648 APIO2014 序列分割
傳送門 首先容易證明,得分和切的順序沒有關係 所以直接預設先切左邊再切右邊就好了 然後顯然可以 dp 一開始想的是設 f i j 表示切了 i 次,此次把 j 和 j 1 分開,得到的最大價值 那麼顯然列舉上一次切的位置 k 那麼 f i j f i 1 k sum j sum k sum n su...