將乙個長度為\(n\)的序列分成\(k\)段,每次分割一段長度\(\ge 2\)的序列,
得分為兩邊序列元素和的乘積,求最大得分
\[2\leq n\leq100000,1\leq k\leq\min\,0≤a[i]≤10^4
\]我們發現一對元素\((i,j)\)產生貢獻\(a[i]a[j]\)的條件是分割後元素不在同一段裡
於是我們知道一對元素產生是否產生貢獻分割順序無關
那麼這道題就變成了序列分段問題
設\(f[i][k]\)表示\([1,i]\)的序列被分為\(k\)段的最大貢獻,\(s[i]=\sum_^a[j]\),有
\[f[i][k]=max_^(f[j][k-1]-s[j]^2+s[i]s[j])
\]此時可以斜率優化維護上凸包,
插點\((s[i],f[i][k-1]-s[i]^2)\),詢問\(k_i=-s[i]\),
由於斜率單調遞減,同樣是可做的
然而這裡有另外一種思路
如果把長度為\(n\)的序列分為\(n-1\)段,
由上可知得分為\(\sum_^\sum_^[i!=j]a[i]a[j]\)
而當一對元素\((i,j)\)不產生貢獻\(a[i]a[j]\)時,他們在同一段裡
於是我們可以求反貢獻的最小值,即對於每一連續段\([i,j]\),
其反貢獻為\(\sum_^\sum_^[k!=l]a[k]a[l]\)
那麼這題可能可以用區間dp做?我還是老老實實寫斜率dp吧
設\(f[i][k]\)表示\([1,i]\)的序列被分為\(k\)段的最小反貢獻,\(t[i]=\sum_^a[j]^2\),有
\[f[i][k]=min_^[f[j][k-1]+\frac((s[i]-s[j])^2-(t[i]-t[j]))]
\]\[=min_^(f[j][k-1]+\frac(s[i]^2+s[j]^2-2s[i]s[j]-t[i]+t[j]))
\]\[=min_^(f[j][k-1]+\frac(s[j]^2+t[j])-s[i]s[j])+\frac(s[i]^2-t[i])
\]那麼我們用普通的斜率優化插點\((s[j],f[j][k-1]+\frac(s[j]^2+t[j]))\)
(注意插點順序),詢問\(k_i=s[i]\)即可,
最後答案為\(\frac(s[n]^2-t[n])-f[n][k+1]\)
小細節:
(1)
該題可以先列舉\(k\)然後列舉\(i\)一層一層做,
或者維護\(k+1\)個凸包,然後倒著插點(!!!)
(2)
該題既可以通過維護上凸包求最大值,
也可以通過維護下凸包求最小值
(3)
注意題中\(a[i]\ge0\),因此\(dx\)有可能為0,直接算斜率的童鞋們要注意啦
#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#define mp make_pair
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define rg register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vectorvi;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int n=100010;
const int k=202;
il ll read()
il void file()
struct node;dequeq[k];
ll n,k,a[n],s[n],t[n],f[n][k];
il void insert(ll t,node q)
il ll query(ll t,ll k)
vi sol;
il void print(int i,int j)
}int main()
for(rg int i=0;i<=k;++i)insert(i,(node));
for(rg int i=1;i<=n;i++));
} }printf("%lld\n",(s[n]*s[n]-t[n])/2-f[n][k+1]);
print(n,k+1);
for(rg int i=sol.size()-1;~i;--i)
printf("%d ",sol[i]);
return 0;
}
最後鳴謝大佬yyb APIO 2014 序列分割
題目鏈結 演算法 首先 我們發現將一段序列切成若干段所獲得的收益與順序無關 於是我們可以用fi,j表示切i次 前j個數的最大收益 令sumi表示ai的字首和 顯然 fi,j max 斜率優化即可 此題記憶體限制較緊 可以使用滾動陣列優化空間複雜度 時間複雜度 o nk includeusing na...
APIO2014 序列分割
嘟嘟嘟 複習一下斜率優化,感覺已經忘得差不多了 這題切入點在與答案跟切的順序無關。證明就是假如有三段權值分別為 x,y,z 那麼這兩刀不管按什麼順序切,得到的結果都是 xy xz yz 然後就可以dp。令 dp i j 表示前 i 個數切 j 刀的最大得分,於是就有 dp i j max 觀察這個式...
APIO2014 序列分割
題目鏈結 你正在玩乙個關於長度為 n 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 k 1 個非空的塊。為了得到 k 1塊,你需要重複下面的操作 k 次 選擇乙個有超過乙個元素的塊 初始時你只有一塊,即整個序列 選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。每次操作後你將獲得那兩個新產生...