日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

斜率优化 笔记

發(fā)布時(shí)間:2024/3/12 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 斜率优化 笔记 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

說道斜率優(yōu)化,我就想起今年下半年 湖南2008年的一個(gè)題。相信大家也不陌生(如果您是第一次學(xué)斜率優(yōu)化,那估計(jì)挺陌生的)。題目叫:HNOI2008 玩具裝箱TOY。題意大概是這個(gè)樣子:

題意簡述

給你一個(gè)序列a[1,n]a_{[1,n]}a[1,n]?和一個(gè)常數(shù)kkk。請你把這個(gè)序列分成若干段。定義:一個(gè)段[l,r][l,r][l,r]需要占用的空間XXX就等于r?l+∑i=lrair-l+\sum\limits_{i=l}^{r} a_ir?l+i=lr?ai?,然后需要的花費(fèi)就是(X?k)2(X-k)^2(X?k)2。其中這個(gè)XXX沒有限制,珂以無限長(只不過不是最優(yōu)就是了)。請求出所有段的花費(fèi)的最小值。

暴力思路

如果您來看斜率優(yōu)化的話,相信您也不難退出這個(gè)題的暴力dpdpdp。設(shè)dp[i]dp[i]dp[i]表示前iii個(gè)數(shù)分成一些段使得總花費(fèi)最小。那么,dp[i]=mindp[j]+cost(j+1,i)dp[i]=min{dp[j]+cost(j+1,i)}dp[i]=mindp[j]+cost(j+1,i)。其中cost(j+1,i)cost(j+1,i)cost(j+1,i)表示從j+1j+1j+1iii這些數(shù)在一段的花費(fèi)。為了稍微快一點(diǎn),設(shè)sumsumsum表示aaa的前綴和。那么cost(j+1,i)cost(j+1,i)cost(j+1,i)就等于[(i?j?1+sum[i]?sum[j])?l]2[(i-j-1+sum[i]-sum[j])-l]^2[(i?j?1+sum[i]?sum[j])?l]2

但是這個(gè)dpdpdpO(n2)O(n^2)O(n2)的。能不能再快一點(diǎn)呢?(嚴(yán)格來講,你必須要再快一點(diǎn),要不然這個(gè)時(shí)間就卡不過去)

正片開始:斜率優(yōu)化

把關(guān)于iii的項(xiàng)和關(guān)于jjj的項(xiàng)單獨(dú)提出來。變成:

設(shè)a(x)=x+sum[x],b(x)=x+sum[x]+l+1a(x)=x+sum[x],b(x)=x+sum[x]+l+1a(x)=x+sum[x],b(x)=x+sum[x]+l+1。那么原式等于(a(i)?b(j))2(a(i)-b(j))^2(a(i)?b(j))2

稍稍改變jjj的定義,令jjj是滿足條件中最優(yōu)的jjj

那么:(推式子警告)

dp[i]=dp[j]+(a(i)?b(j))2dp[i]=dp[j]+a(i)2?2a(i)b(j)+b(j)2dp[i]+2a(i)b(j)?a(i)2=dp[j]+b(j)2dp[i]=dp[j]+(a(i)-b(j))^2\\ dp[i]=dp[j]+a(i)^2-2a(i)b(j)+b(j)^2\\ dp[i]+2a(i)b(j)-a(i)^2=dp[j]+b(j)^2 dp[i]=dp[j]+(a(i)?b(j))2dp[i]=dp[j]+a(i)2?2a(i)b(j)+b(j)2dp[i]+2a(i)b(j)?a(i)2=dp[j]+b(j)2

把這個(gè)式子放到平面直角坐標(biāo)系上,以b(j)b(j)b(j)xxxdp[j]+b(j)2dp[j]+b(j)^2dp[j]+b(j)2yyy

對于每個(gè)jjj來說,點(diǎn)(b(j),dp[j]+b(j)2)(b(j),dp[j]+b(j)^2)(b(j),dp[j]+b(j)2)就是一個(gè)決策點(diǎn)了。

而且,顯然這是一個(gè)直線的關(guān)系,它的斜率就是2a(i)2a(i)2a(i),截距是dp[i]?a(i)2dp[i]-a(i)^2dp[i]?a(i)2。我們把直線向上平移a(i)2a(i)^2a(i)2,就是最小的dp[i]dp[i]dp[i]。由于a(i)2a(i)^2a(i)2的值是確定的(我們在找jjj的過程中,iii是不會變的),所以在同一個(gè)iii里面,我們相當(dāng)于要讓截距最小。

這樣,對于每個(gè)iii(注意,和上面不一樣,不在同一個(gè)iii里面了),珂能作為最優(yōu)點(diǎn)選擇出來的點(diǎn)應(yīng)該組成一個(gè)下凸包(因?yàn)?span id="ozvdkddzhkzd" class="katex--inline">a(i)a(i)a(i)是單調(diào)遞增的,所以斜率單調(diào)遞增,即組成下凸包)。

a(i)a(i)a(i)的單調(diào)遞增性我就不講了)

為啥?考慮這種情況:

AAABBBCCC是珂供選擇的三個(gè)決策點(diǎn))

當(dāng)前的話,如果AAA還沒滾蛋,應(yīng)該是AAABBB優(yōu)的。如圖

隨著斜率的增加,也許會出現(xiàn)CCCAAABBB都優(yōu)的情況。如圖:

容易證明,CCC此時(shí)一枝獨(dú)秀,AAABBB都珂以滾蛋了。這兩種情況有一個(gè)共同點(diǎn),就是BBB都不能再優(yōu)了。anyway,滾蛋吧。

還有一種情況(肯定還有,只有剛剛那一個(gè)是沒法保證正確性的),就是最前面兩個(gè)元素還要滿足一個(gè)條件:第一個(gè)點(diǎn)和第二個(gè)點(diǎn)之間的斜率要>=2a(i)>=2a(i)>=2a(i),否則第一個(gè)就再也不珂能作為最優(yōu)解出現(xiàn)了,因?yàn)榇藭r(shí)隨著斜率的單調(diào)遞增,后面的斜率肯定會更大,在當(dāng)下的2a(i)2a(i)2a(i)的斜率中第二個(gè)都比第一個(gè)優(yōu),后面的話就不知道優(yōu)到哪里去了。所以第一個(gè)就再起不能,滾了。

如圖:

還是剛剛那張圖,不過是另一種滾蛋方法。此時(shí)紅色直線的斜率=2a(i)2a(i)2a(i)=202020。當(dāng)紅色直線斜率為202020的時(shí)候,AAA就沒有BBB優(yōu)了。如果再高一點(diǎn),顯然,還是沒有BBB優(yōu)。所以以后這個(gè)AAA都不珂能比BBB更優(yōu)了。AAA就珂以滾蛋了。

說道這里,我們發(fā)現(xiàn),這個(gè)東西珂以用一個(gè)單調(diào)隊(duì)列維護(hù)。維護(hù)完一個(gè)正確的隊(duì)列之后,Q[head]Q[head]Q[head]就是最優(yōu)解。

設(shè)隊(duì)列為QQQ,首尾分別叫head,tailhead,tailhead,tail

總結(jié)一下,就是要維護(hù)兩個(gè)關(guān)系:

代碼:

#include<bits/stdc++.h> using namespace std; namespace Flandre_Scarlet {#define N 112345#define int long long #define F(i,l,r) for(int i=l;i<=r;++i)#define D(i,r,l) for(int i=r;i>=l;--i)#define Fs(i,l,r,c) for(int i=l;i<=r;c)#define Ds(i,r,l,c) for(int i=r;i>=l;c)#define Tra(i,u) for(int i=G.Start(u);~i;i=G.Next(i))#define MEM(x,a) memset(x,a,sizeof(x))#define FK(x) MEM(x,0)int n,l;int c[N];void R1(int &x){x=0;char c=getchar();int f=1;while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();x=(f==1)?x:-x;}void Input(){R1(n),R1(l);F(i,1,n) R1(c[i]),c[i]+=c[i-1];}int Q[N];int dp[N];int a(int i){return c[i]+i;}int b(int i){return c[i]+i+l+1;}int x(int i){return b(i);}int y(int i){return dp[i]+b(i)*b(i);}int slope(int i,int j)//計(jì)算斜率{return (y(i)-y(j))/(x(i)-x(j));}void Soviet(){int head=1,tail=1;F(i,1,n){while(head<tail and slope(Q[head],Q[head+1])<2*a(i)) ++head;//垃圾決策點(diǎn)出隊(duì)列dp[i]=dp[Q[head]]+(a(i)-b(Q[head]))* (a(i)-b(Q[head]));//Q[head]就是最優(yōu)的決策點(diǎn)。while(head<tail and slope(i,Q[tail-1])<slope(Q[tail-1],Q[tail])) --tail;Q[++tail]=i;//把i加入隊(duì)列}printf("%lld\n",dp[n]);}void IsMyWife(){Input();Soviet();}#undef int //long long } int main() {Flandre_Scarlet::IsMyWife();getchar();getchar();return 0; }

還有一些答疑時(shí)間(根據(jù)作者自身出現(xiàn)的理解問題編寫,以后支持評論功能之后珂能會根據(jù)評論區(qū)中的問題編寫。)

Q:既然Q[head]Q[head]Q[head]是最優(yōu)的,為啥還要存著后面的點(diǎn)呢?
A:后面的點(diǎn)雖然現(xiàn)在不是最優(yōu)的,但是它們很有潛力,等以后斜率上去之后,也許Q[head]Q[head]Q[head]就滾蛋了,后面那些點(diǎn)就變成了最優(yōu)。注意上面,我們說的是珂能成為最優(yōu)的點(diǎn),而不是現(xiàn)在最優(yōu)的點(diǎn)。要為未來著想。

總結(jié)

以上是生活随笔為你收集整理的斜率优化 笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。