[題解]和

[題目描述]

給定一個長度爲n的序列,你每次可以合併相鄰兩個元素,新的元素爲這兩個元素的和。你需要使得若干
次合併之後的序列非降,求最小合併次數。

[數據範圍]

n<=1500

[題解]

      這道題的標程用的是n^2log(n)的dp,所以纔會有奇葩的1500的範圍.

      然而,這道題完全可以在O(n^2)的時間內解決.

      考慮前i個數的決策.如果我們要合併成合法序列後,最後的值最小,那麼我們一定要使合併的次數最小.因爲在如果合併次數最少且最後的值最小的情況下再進行合併,最後的值顯然不會變大,即:不可能出現一種情況,使得合併的次數不是最少而最後面的值最小.因爲我們一切的合併操作都是"被逼"的,所以多合併不可能使最後的數變大,於是上面的結論也可以很容易的想出來.

Code:

program sequence;
type int=longint;
var
        i,j,k,m,n:int;
        a,f,g,s:array[0..1500]of int;
begin
        assign(input,'sequence.in');reset(input);
        assign(output,'sequence.out');rewrite(output);
        read(n);
        for i:=1 to n do begin read(a[i]);s[i]:=s[i-1]+a[i];end;
        fillchar(f,sizeof(f),100);
        fillchar(g,sizeof(g),100);
        f[1]:=0;g[1]:=a[1];
        for i:=2 to n do begin
                for j:=1 to i-1 do begin
                        if(f[j]+i-j-1<=f[i])and(g[j]<=s[i]-s[j])then begin
                                g[i]:=s[i]-s[j];f[i]:=i-j-1+f[j];
                        end;
                end;
        end;
        write(f[n]);
        close(input);close(output);
end.

考試時因爲前兩題太水了,本以爲第三題會搞一道難題防AK的,所以就隨便打了個貪心,只搞到了10分.知道正解這麼簡單後簡直想吐血= =.

有很多人覺得這樣dp的正確性不好證,其實這樣做的正確性是顯然的,到時候我再將完整版題解搞上來.

//=================================================================================================

好了,考也考完了.現在我來講一下這道題目的線性做法.


將方程變形得到:

F[i]=min(f[j]-j)+i-1,G[j]+s[j]<=s[i].

顯然,F[j]-j隨j單調不增,s[i]單調上升.

於是,我們維護這樣一個單調隊列,使得下標單調遞增(即F[j]-j單調遞減),G[j]+s[j]單調上升,之後怎麼做應該都會了吧.


BY QW

轉載請註明出處


發佈了45 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章