【校內模擬】【18-10-24】 小C的數組 【DP】【二分】

題解

1.0 認(hu)真(luan)分析(建議跳過)

不就是維護相鄰數字的差的最大值最小嗎?簡單~

  1. 把n-1個數對丟到優先隊列裏面,維護一下差值以及位置.
  2. 更新的時候就把靠前的值改了,然後丟掉,再把靠後的值與數對前面那個值合併一下丟進隊列。
  3. 所有丟掉的數打上標記,然後最後掃一遍,這些有標記的地方取平均值即可。

我在說什麼玩意兒
比如 7 3 8 9,k=1,丟進去(7,3) (3,8) (8,9),先把(3,8)拿出來,把3打標記(比如弄成inf),然後把(7,8)壓回去。最後輸出的時候掃一遍得到的是 7 inf 8 9,有inf的地方取前後兩個值的中間值,如果是一串inf就用左側數和右側數的差值除以inf的個數。

然後我開開心心的爆零了

(上面這個算法爲什麼不對,博主暫時還給不出什麼正經的證明(真是抱歉),如果哪位大佬能給出反例自然感激不盡~)

1.1 正解
70pts DP+二分

讀題,發現我們要求的是最大值最小,那就應該自然想到二分答案。

不過這個check函數怎麼寫呢?

首先考慮,對於比二分出的mid還要大的Ai - Ai+1 ,我們肯定要進行更改,那麼我們就記一個當前的數字是多少,記一個修改了多少次,再記一個現在的位置,就有了fi,j,k

如果連修改的機會都用完了還不能使Ai - Ai+1 <mid,那就把二分的下界調高;只要能有一種方案滿足,我們就把二分的上界調低。

(當然要是不二分直接枚舉就只有30pts了

100pts DP改進

思考一下,我們剛纔的dp之所以得不到滿分,就是因爲這個數據範圍變大了,我們沒法用當前數字作爲狀態來轉移了。

那如果我們記錄不了修改的狀態……我們記錄下哪些地方不修改不就行了嗎?

於是乎,用fi表示當前位置是第i個,這之前的所有數字全都修改,後面的數字也全部滿足要求,需要修改多少個數字。

狀態轉移呢?

實際上也比較簡單,我們從n開始倒推,那麼對於狀態fi,首先它前面的全部要改,其次它後面的、不符合要求的肯定也得改。

那啥時候他後面的要改呢?

對於 (j-i)*mid >= (Ai-Ai)的,我們可以得到轉移 fi=min(fi,fj+j-i+1)。這個其實很好理解:如果兩個值之間的差值大於了(j-i)*mid,你怎麼改都不可能改出想要的答案,所以沒法轉移。而對於別的狀態,我們取最小值轉移就可以了。

所以就是 for(i=n;i>=1;i- -)裏面加一個for(j=n;i>=i+1;j- -),最後轉移出來的狀態f1就是使得mid成立所需要的最小修改次數,再根據這個調整上下界就可以啦~

總結

首先是一定一定看到最大值最小這種東西就要用二分!然後再考慮如何去驗證二分的答案是否正確,可以是搜索、DP、區間查詢等等,總之只要能夠檢驗答,都要試一試。

當然首先我們一定要想到二分

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章