1. 最长公共上升序列(LCIS)
在做决策时,同时考虑2个条件. P版源程序.
program lcis;
const
maxn=1000;
var
a,b,num:array[1..maxn] of longint;
l1,l2,n,m,t:longint;
begin
assign(input,'in.in');
assign(output,'out.out');
reset(input);
rewrite(output);
read(n);
for l1:=1 to n do
read(a[l1]);
read(m);
for l1:=1 to m do
read(b[l1]);
fillchar(num,sizeof(num),0); //表面看起来num似乎不需要初始化,但其实需要……
for l1:=1 to n do //每轮更新a[l1]=b[x]的所有情况
begin
t:=0;
for l2:=1 to m do
if a[l1]>b[l2] then //只要出现小的就可以更新
if num[l2]>t then
t:=num[l2]
else
else
if a[l1]=b[l2] then
if t+1>num[l2] then
num[l2]:=t+1;
end;
t:=0;
for l1:=1 to m do
if num[l1]>t then
t:=num[l1];
writeln(t);
close(input);
close(output);
end.
2. DP的斜率优化
POJ 1180
解析:
这个题目在斜率优化上算是很经典的了的,题目大意也不难理解。
这样吧,慢慢来。假如现在不考虑它的数据范围,如果要你裸做的话……搜索?不可能。Dp吧,方程大概可以这样想出来:
从前往后做的话……不好搞的。所以倒推吧。用F[ i ] 表示从 i 开始到 N 已经全部做完了的最小代价。这样转移会很方便的~
F[ i ] := Min( F[j] + (S + sumT[i] - sumT[j]) * sumF[i] )
这样的话转移的这一段工作的代价不仅仅在这个地方计算了一次,在算前面的地方也同样计算了一次。所以就可以证明这个方程的正确性啦~
然后考虑数据范围之后就发现根本没有办法做(废话……),这样做当然不行啦。需要优化一下,不能在状态的地方优化就在转移的地方优化吧。
考虑转移到 i 这个地方来的时候是分别从 j1 j2 (J1<J2)转移过来的,那么这两个值什么时候有大小关系呢?来算算。假如从J1转移过来的时候更优的话:
( F[ j1 ] + ( S + sumT[ i ] - sumT[ j1 ] ) * sumF[ i ] ) - ( F[ j2 ] + ( S + sumT[ i ] - sumT[ j2 ] ) * sumF[ i ] ) < 0
=> F[ j1 ] - F[ j2 ] + sumF[ i ] * ( sumT[ j2 ] - sumT[ j1 ] ) < 0
=> F[ j1 ] - F[ j2 ] < sumF[ i ] * ( sumT[ j1 ] - sumT[ j2 ] )
因为 j1 < j2 所以 ( sumT[ j1 ] - sumT[ j2 ] ) > 0
=> ( F[ j1 ] - F[ j2 ] ) / ( sumT[ j1 ] - sumT[ j2 ] ) < sumF[ i ]
那么如果有两个转移满足上面的要求那么就可以直接无视掉J2了不是么?而且还可以知道,sumF[ i ] 是递增的,那么只要有一次无视掉了J2那么以后都不会从这里转移过来了塞^.^
现在就好办了,就可以直接用一个队列优化来维护这个值就可以了,队列里面保存可以转移过来的位置,然后套上面的方程,判断是否可以,然后做,就可以啦~
恩~完美的优化了一维~
程序:
Program Gp ;
Const
maxn = 10001 ;
Var
sumT , sumC : array[ 0 .. maxn ] of longint ;
f : array[ 0 .. maxn ] of longint ;
que : array[ 0 .. maxn ] of longint ;
n , m : longint ;
Procedure Init ;
var
i , a , b : longint ;
begin
readln( n ) ; readln( m ) ;
for i := 1 to n do readln( sumT[ i ] , sumC[ i ] ) ;
sumT[ n + 1 ] := 0 ; sumC[ n + 1 ] := 0 ;
for i := n downto 1 do sumT[ i ] := sumT[ i + 1 ] + sumT[ i ] ;
for i := n downto 1 do sumC[ i ] := sumC[ i + 1 ] + sumC[ i ] ;
end ;
Function Sploe( j1 , j2 : longint ) : extended ;
begin
Sploe := ( f[ j1 ] - f[ j2 ] ) / ( sumT[ j1 ] - sumT[ j2 ] ) ;
end ;
Procedure Dp ;
var
l , r , i : longint ;
begin
f[ n + 1 ] := 0 ;
l := 1 ; r := 1 ; que[ 1 ] := n + 1 ;
for i := n downto 1 do
begin
while ( r > l ) and ( Sploe( que[ l ] , que[ l + 1 ] ) <= sumC[ i ] ) do Inc( l ) ;
f[ i ] := f[ que[ l ] ] + ( m + sumT[ i ] - sumT[ que[ l ] ] ) * sumC[ i ] ;
while ( r > l ) and ( Sploe( que[ r - 1 ] , que[ r ] ) >= Sploe( que[ r ] , i ) ) do Dec( r ) ;
Inc( r ) ; que[ r ] := i ;
end ;
writeln( f[ 1 ] ) ;
end ;
Begin
Init ;
Dp ;
end .