luogu4360 鋸木廠選址 (斜率優化dp)

2022-04-30 01:15:12 字數 1536 閱讀 9994

設:

sw[i]為1..i的w之和

sd[i]為1到i的距離

cost[i]為把第乙個鋸木廠建在i帶來的花費

all[i,j]為把i..j所有木頭運到j所需要的花費

所以$all[i,j]=cost[j]-cost[i-1]-sw[i-1]*(sd[j]-sd[i-1])$

我們設第2個鋸木廠建在i所帶來的最小花費為f[i],則$f[i]=min\$

把all化掉,最終變成$f[i]=min\$

這樣的話,如果直接做,複雜度是$o(n^2)$的

考慮優化,我們嘗試比較在i固定時,f[j1]和f[j2]的值(j1先假設$f[j1]-f[j2]<0$,也就是j1是較優解

那麼可以得到$\frac>sd[i]$

發現右端隨i單增,而且左端呈現斜率的形式

那麼也就是說,如果在某次i++以後,某兩個j1,j2的斜率那麼可以維護乙個佇列,保證j1這樣在每次i++的時候,先從隊頭向後把斜率然後在統計完i的答案以後,i也可以作為第乙個伐木廠了,就把它按照性質從隊尾插進去

也就是說,對於隊尾的兩個元素t-1和t,若t.i間斜率》t-1.t間斜率,直接把i插到隊尾;

若不是,則踢掉t然後繼續做(此時的t絕對不會是最優解了,因為t-1與i間斜率佇列裡只剩乙個點的話就談不來斜率了..就不做了...

然後做的時候可以把比較斜率的除法改成乘法,防止出鍋

每個點最多進隊一次,出隊一次,所以複雜度是o(n)的

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

#define ll long long int

9using

namespace

std;

10const

int maxn=20005;11

12ll rd()

15while(c>='

0'&&c<='

9') x=x*10+c-'

0',c=getchar();

16return x*neg;17}

1819

intn,w[maxn],d[maxn];

20ll sw[maxn],sd[maxn],cost;

21int

q[maxn],head,tail;

2223 inline bool judge1(int j1,int j2,int i)

24 inline bool judge2(int j1,int j2,int j3)

25 inline int

get(int i,int j)

2627

intmain()cost+=sw[n]*d[n];sd[n+1]=sd[n]+d[n];

35 head=tail=1;q[1]=1;36

int ans=2e9+10;37

for(i=2;i<=n;i++)printf("

%d\n

",ans);

4344

return0;

45 }

鋸木廠選址

這是我斜率dp第乙個沒有一遍ac的,原因是第一遍忘開long long了。這一題比較特殊,細心的同學一定發現了,遞推式不帶f。為了方便,設d陣列的字尾和為sd i sd i 1 d i 設k陣列的字首和為sk i sk i 1 k i k i 即是題目中的w i 設f i 為第二個鋸木廠選在i時的最...

Two Sawmills 鋸木廠選址

斜率優化dp,應該說是第一道斜率優化dp了,推公式的時候各種坑,還是參照了hzq神牛的思路,細節方面稍有不同,為了思維方便,我先將給出的序列翻轉了,也就是把從山頂到山下的點順序邊成了從山下到山頂,編號從1開始,第乙個點即為海拔最低的伐木場,所以共有n 1個點,w i 表示第i個點的重量,dist i...

洛谷P4360 CEOI2004 鋸木廠選址

做兩遍dp,dp k i 表示前i個位置放k個鋸木廠的最小值 先把整個順序反過來,那麼0的位置就是山腳的鋸木廠 設sum i f i 是sum i w i 字首和,f2 i 是w i 的字首和 dp 1 i f i f k sum k 1 f2 i f2 k dp 0 k 展開成f2 k sum k...