設:
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...