斜率優化題目大家肯定都做得不少了,有一些題目查詢插入點的x座標和查詢斜率都不單調,這樣就需要維護動態凸包並二分斜率。(例如bzoj1492)
常規的做法是cdq分治或手寫平衡樹維護凸包,然而如果我不願意寫分治,也懶得打平衡樹,怎麼辦呢?
沒關係,今天我告訴你怎麼用乙個set維護這種凸包。
首先orzlh,沒什麼特殊意義,只是單純的orz。
我們定義f[i]表示在第i天能擁有的金券組數,按照第i天的比例。
那麼,我們要把前面的金券在今天賣出獲得最多的錢,並在今天進行**。
所以,f[i]=max((f[j]*a[i]+f[j]/rate[j]*b[i])/(a[i]+rate[i]*b[i]))。
除下去的東西是乙個常數,扔掉。
然後我們就有:
t=max(a[i]*(f[j])+b[i]*(f[j]/rate[j]))。
如果我們把f[j]看做x,f[j]/rate[j]看做y,我們有:
t=a*x+b*y,兩邊同時除以b,得到:
t/b=(a/b)x+y
y=(t/b)-(a/b)*x
好的,現在我們有一條斜率為-(a/b)的直線,要找乙個點使之截距最大。
這樣我們維護乙個右上1/4凸殼即可。
怎麼維護?
我們考慮不用斜率優化,單純水平序維護凸包,那麼點是按照x座標單增在平衡樹上排列的。
現在我們在每個點維護他與後面點連線斜率,我們會發現:這個斜率是單降的。
所以,我們可以通過適當地轉換cmp函式,來通過乙個set完成兩種比較。
我們定義:
1插入就是正常凸包插入,最後再維護一下斜率就行了。注意彈出左邊後迭代器會失效,所以需要重新lower_bound一下。(可能原來你的迭代器是原來的end,結果彈出左邊後end改變了,兩個end不同,然後你去彈出右邊,訪問無效迭代器,就直接re了)int cmp; //
0 compare x , 1 compare slope .
2struct
point
8 friend point operator - (const point &a,const point &b) ;10}
11 friend double
operator * (const point &a,const point &b)
14 inline double calc(double a,double b) const
17};
18set
st;
1 inline void pop_right(set查詢的話就更改一下比較函式,然後特判一下邊界防止re就好。::iterator nxt,const point &p) 9}
10 inline void pop_left(set
::iterator prv,const point &p) 17}
18 inline void insert(const point &p)
31 nxt = lst , ++nxt;
32if(nxt!=st.end()) else
41 }
1 inline double query(const所以整體**:intid) ); //
it can't be st.end() if st isn't empty .
5if( it==st.end() ) return0;
6double ret = it->calc(a[id],b[id]);
7if( it !=st.begin() )
11return
ret;
12 }
bzoj1492:
1 #include2 #include3 #includeview code4 #include5
using
namespace
std;
6const
int maxn=1e5+1e2;78
int cmp; //
0 compare x , 1 compare slope .
9struct
point
15 friend point operator - (const point &a,const point &b) ;17}
18 friend double
operator * (const point &a,const point &b)
21 inline double calc(double a,double b) const
24};
25set
st;26
double
a[maxn],b[maxn],rate[maxn],f[maxn],ans;
2728 inline void pop_right(set
::iterator nxt,const point &p) 36}
37 inline void pop_left(set
::iterator prv,const point &p) 44}
45 inline void insert(const point &p)
58 nxt = lst , ++nxt;
59if(nxt!=st.end()) else68}
69 inline double query(const
intid) ); //
it can't be st.end() if st isn't empty .
73if( it==st.end() ) return0;
74double ret = it->calc(a[id],b[id]);
75if( it !=st.begin() )
79return
ret;80}
8182
intmain() );90}
91 printf("
%0.3lf\n
",ans);
92return0;
93 }
不得不說stl的set跑的還是挺快的。
這裡是回檔後的世界,無論你做什麼,你都一定會這樣做。
而我努力改變命運,只是為了防止那一切重現。
(來自某中二病晚期患者(不))
8 教你用 opencv 訓練屬於自己的模型
當前模型訓練將在win10系統下去完成,首先還是安裝好opencv,我這裡安裝在了 d opencv 目錄下。為了訓練自己的模型,首先我們需要將 d opencv build x64 vc15 bin 目錄下的 opencv createsamples.exe opencv traincascade...
教你用記事本做整人的另類簽名
教你用記事本做整人的另類簽名 2011年12月24日 今天來教大家怎麼製作這樣的簽名圖。很簡單的,只要運用vbs指令碼語言就行了.1.執行windows自帶的記事本,在裡面輸入以下內容 msgbox 對不起,您灌水太多需要重新啟動計算機。chr 10 確定要重啟嗎?33,重新啟動計算機 2.儲存文字...
教你用記事本做整人的另類簽名
教你用記事本做整人的另類簽名 2011年12月24日 今天來教大家怎麼製作這樣的簽名圖。很簡單的,只要運用vbs指令碼語言就行了.1.執行windows自帶的記事本,在裡面輸入以下內容 msgbox 對不起,您灌水太多需要重新啟動計算機。chr 10 確定要重啟嗎?33,重新啟動計算機 2.儲存文字...