bzoj3156防御准备
3156: 防御准备
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1349 Solved: 605
[Submit][Status][Discuss]
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
Sample Output
18
HINT
1<=N<=10^6,1<=Ai<=10^9
题解
首先把序列倒过来方便处理。
令f[i]表示第i个位置放守卫塔的情况下前i个全部通过检查的最小花费,则f[i]=min{f[j]+(i-j)(i-j-1)/2},发现时间复杂度不对,显然可以看出来用斜率优化。
设f[j]+(i-j)(i-j-1)/2<=f[k]+(i-k)(i-k-1)/2,移项化简得到f[j]+j(j+1)-(f[k]+k(k+1))<=2i(j-k)斜率优化的形式,然后单调队列维护。
其实都是套路。
1 /************************************************************** 2 Problem: 3156 3 User: 1090900715 4 Language: Pascal 5 Result: Accepted 6 Time:6256 ms 7 Memory:19760 kb 8 ****************************************************************/ 9 10 program j01; 11 var f,a:array[0..1000086]of int64; 12 n,i,j:longint; 13 l:array[0..1000086]of longint; 14 h,tail:longint; 15 pre:int64; 16 17 function min(a,b:int64):int64; 18 begin 19 if a<b then exit(a) else exit(b); 20 end; 21 22 function KK(k,j:longint):double; 23 begin 24 exit((2*(f[j]-f[k])+int64(j)*(j+1)-int64(k)*(k+1))/(2*(j-k))); 25 end; 26 27 begin 28 readln(n); 29 for i:=1 to n do 30 read(a[n-i+1]); 31 a[n+1]:=0; 32 h:=1;tail:=1;l[tail]:=1;f[1]:=a[1]; 33 for i:=2 to n+1 do 34 begin 35 while (h<tail)and(KK(l[h],l[h+1])<=i) do inc(h); 36 pre:=l[h]; 37 f[i]:=a[i]+f[pre]+((i-pre)*(i-pre-1) div 2); 38 while (h<tail)and(KK(l[tail],i)<=KK(l[tail-1],l[tail])) do dec(tail); 39 inc(tail);l[tail]:=i; 40 end; 41 writeln(min(f[n],f[n+1])); 42 end.