1. 程式人生 > >【筆記篇】斜率優化dp(三) APIO特別行動隊

【筆記篇】斜率優化dp(三) APIO特別行動隊

旁聽了一波給舒老師和學弟的pkuwc面試講座…

這裡有一段隱身的吐槽, 請反白觀看. 不想看的跳過這一段看似空白的東西就好了…
剛開始ATP學姐給我們講了自己面試的時候的事情..描繪了一下當時面試的場面和當時問的問題…ATP學姐太可愛了OvO可能準備的也不是很充足 用了好多的”然後” “就是”之類的, 自己也在吐槽, 老師後來也槽來著, 不過還是超可愛n(≧▽≦)n旁邊老師在記錄, 尤其記下了一個什麼”你認為學習資訊男生和女生有什麼區別?”的問題..可是這種問題怎麼可能問男生啊講道理, 然後學姐講完之後就是shallwe大爺來講, shallwe大爺還準備了稿子, 然後就講了一些面基技巧.. 但是也是比較老生常談的東西, 之前參加各種各樣的風采大賽回答問題的時候也就是那一套之類的 小時候還能做到, 現在反而越來越不行了.. 然後講了各種各樣的問題, 說是問的問題都在blog裡面.. 老師還說要blog的地址來給學弟學妹什麼的(那也就是包括我們咯), 但是聽完回來一看這blog裡的東西能給老師看?! 各種吐槽甚至還有吐槽面試培訓的.. 然後他們就回去學習了= =
老師就開始種講評, 還讓兩個人分別回答了上面說的男女區別問題 然後兩個都做出了比較”片面”的回答, 老師就說要往什麼三個方面想之類的說了一堆, 反正就是不懟人的同時優雅地裝逼的技巧,

什麼在北大不說清華比北大強之類的, 說了確定不是石樂志麼= =然後再就是”你有什麼缺點”, 聽說年年問..大家準備好的答案都能倒著背了好麼就說要找個”不是缺點的缺點”, 然後兩個人都說自己比較執著啊… 就不能找點有創意的麼←←, 感覺全世界都有執著得有點傻這個缺點… 要我的話可能會說自己好奇心過強? 反正就這麼著吧. 然後還有什麼進門關門鞠躬瞅瞅有沒有廢紙倒拖把什麼的… 反正就是一些雞湯文裡描寫的面試的細節問題, 還有著裝問題, 我覺得只要不是明顯違和的穿女裝應該都不是什麼大問題吧←對沒錯哪怕是可愛的男孩紙穿女裝其實也是可以噠~(≧▽≦)/~兩個人又練了一波關門鞠躬之類的 終於煎熬地熬過去了.. 然後趕緊去了個廁所 畢竟半下午+半晚上沒有去了.. 回來之後就調這個題 不過很快就調A了這還比較和善..
嗯 主要原因是這次的luogu沒有出鍋...

===我===是===一===條===分===割===線===我===也===是===一===扇===傳===送===門===

繼續吐槽, 不過這次跟題目有關了.. 聽完回來就繼續寫這道題啊…
這道題顯然支援O(n)的做法, (感覺1e6的話套個log就不是很靠譜了)
那就是要優化, 就是要化式子嘛..然後剛開始以為這個題是

i=1n(ax2i+bxi+c)=ai=1nx2i+bsn+nc
然後最大化ni=1x2i之後直接輸出af[n]+bs[n]+nc的大水題,
但是發現好像樣例差了好多好多…結果發現自己快讀沒讀負數…
然後改完之後輸出負數了… 手玩了一下發現好像這個n
c
n好像不一定是題目裡給的n
那就不能這麼化式子了, 就開始重新化.. 還是得從狀態轉移方程入手…
f[i]=max{f[j]+a(s[i]s[j])2+b(s[i]s[j])+c}(j[1,i))
然後去括號
f[i]=f[j]+as[i]22as[i]s[j]+as[j]2+bs[i]bs[j]+c
移項能得到
f[j]+as[j]2bs[j]=2as[i]s[j]+f[i](as[i]2+bs[i]+c)
由於題目中已經給了5<a<1, 所以斜率一定是<0的, 而f[j]+as[j]2bs[j]直觀上很明顯是遞減的. 我們考慮凸性對結果的影響.
這裡寫圖片描述
我們考慮中間的點在位於兩個斜率中間(大於大斜率小於小斜率顯然不優就不考慮了)的情況.
發現如果是位於下凸殼的點是不優的, 而位於上凸殼的點是優的, 我們就要維護一個上凸殼.

而這裡的斜率2as[i]顯然是遞減的(絕對值遞增), 所以
這裡寫圖片描述
如果一個斜率一旦已經小於(絕對值大)於隊首的邊, 那麼隊首的點在以後也不會優了 我們讓隊首出隊即可.
依然是維護一個單調佇列.
然後就沒有了. 程式碼: 1A了哈哈哈哈 (放肆地笑ing…)

#include <cstdio>
const int N=16+6;
typedef long long LL;
LL f[N],s[N]; int q[N],h,t,a,b,c,n;
inline int gn(int a=0,char c=0,int f=1){
    for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar()) a=a*10+c-'0'; return a*f;
}
inline double slope(int x,int y){
    return 1.0*(f[x]+a*s[x]*s[x]-b*s[x]-f[y]-a*s[y]*s[y]+b*s[y])/(s[x]-s[y]);
}
int main(){ n=gn(); a=gn(); b=gn(); c=gn();
    for(int i=1;i<=n;++i) s[i]=s[i-1]+gn();
    for(int i=1;i<=n;++i){
        while(h<t&&slope(q[h],q[h+1])>=2*a*s[i]) ++h;
        f[i]=f[q[h]]+a*(s[i]-s[q[h]])*(s[i]-s[q[h]])+b*(s[i]-s[q[h]])+c;
        while(h<t&&slope(q[t],q[t-1])<=slope(q[t],i)) --t;
        q[++t]=i;
    } printf("%lld",f[n]);
}