bzoj1911 CodeVS1318 特別行動隊

2021-07-05 09:38:53 字數 1418 閱讀 8856

題意:給出n個數,要求把它們分成若干個連續段。對於乙個數之和為s的連續段,得分為f(s)=a*s*s+b*s+c,其中a,b,c已經給定且a是負數。求最大的總得分。要求線性複雜度。

很容易想到這道題的乙個dp演算法:設dp[i]為前i個數分成若干個連續段能獲得的最大的總得分,且dp[0]=0。則有dp[i]=max(j但是,這樣的演算法是二次方的,不能滿足本題的要求。應該注意到本題中分數的計算方式的特殊性,來尋找突破口。

令s[i]=w[1]+...+w[i],則dp[i]=max(0<=j=a*s[i]*s[i]+b*s[i]+c+max(0<=j如果令k=2*a*s[i]+b,x=s[j],y=dp[j]+a*s[j]*s[j],g為max{}的內容,則有y=k*x+g。看到這個式子,如果熟悉斜率優化dp,就很容易做出這個題目了。

但是,很多人並不了解斜率優化dp,於是我複製了一段話,並稍作修改:

得到這個式子之後,我們可以看到,k是乙個常數(由當前列舉的i在o(1)時間內計算得出)。將這個式子看成是乙個直線的函式表示式的話,k就是斜率,也就是說這是乙個斜率固定的直線。

y和x則是和j有關的常量。而j的這些值應該都已經在之前計算過了。(因為j再加上很關鍵的一點。隨著i的增加,點的座標是單調不下降的(s[i]),直線的斜率也是單調不降的(2*s[i]+b)!

滿足這兩個單調性,我們就可以利用單調佇列,來維護乙個凸殼。因為我們要找g的最小值,所以要維護乙個下凸殼。方法和之前那篇數形結合題一樣,類似garham求凸包的演算法。

之所以可以用單調佇列是因為座標和斜率都滿足單調性的話,可以證明每個點如果不是某個i的最優決策,也不能會是之後的i的最優決策,可以被拋棄。

因為每個i只會進出佇列一次,所以時間複雜度降為o(n),只需要儲存單列就可以,空間複雜度為o(n),比較完美地解決了這個問題。 

**中有一些話和以上內容稍有出入:

因為各數段的s之和必然是n個數的和,所以b*s這一項可以直接移到最外部。

維護下凸殼時,基於各橫縱座標單調上公升的特殊性,直接判斷斜率的大小來刪點。

並不是真正的佇列實現,而是模擬兩個指標i和j,隨著i的增加j在原基礎上增加。

**:#include#define rpt(x) for(i=1;i<=x;i++)

#define maxn 1000005

struct point;

long double slope(point a,point b)

point p[maxn],t;

long long a,c,s[maxn],f[maxn],tmp;

int e[maxn],g[maxn],n,i,j,k,m,a,b,c;

long long ans;

int main()

k=1;

m=0;

rpt(n){

f[i]=a*s[i]*s[i]+c;

while((k1)&&(slope(p[m],t)

codevs1911 孤島營救問題

1944 年,特種兵麥克接到國防部的命令,要求立即趕赴太平洋上的乙個孤島,營救被敵軍俘虜的大兵瑞恩。瑞恩被關押在乙個迷宮裡,迷宮地形複雜,但幸好麥克得到了迷宮的地形圖。迷宮的外形是乙個長方形,其南北方向被劃分為n 行,東西方向被劃分為m列,於是整個迷宮被劃分為n m 個單元。每乙個單元的位置可用乙個...

codevs 1911 孤島營救問題

為了分析方便,可以先做乙個題目簡化。去掉 鑰匙 這個條件,那麼就是乙個bfs或者spfa 現在加上該條件。如本題只給出最多兩種鑰匙,當然你可以繼續堅持bfs等方式,時間不會太差。但是一旦鑰匙種類上公升至15的時候,就有太多情況需要處理 光說你寫bfs的if就是很長的過程,但個人認為時間複雜度依舊能過...

bzoj 1911斜率優化

這個題為什麼有個 關於斜率優化又有了新的感悟 對於次優解的排除 假設對於i來說l是次優解。即滿足k q l q l 1 k i 時,l 1比l更優 k q l q l 1 表示這兩個點連成一條線的斜率,k i 表示在i處那根線的斜率,這個很容易就可以證明 對於提前排除不可能的解 假設r是考慮排除的點...