[题解]和

[题目描述]

给定一个长度为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

转载请注明出处


评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值