bzoj3156防御准备

3156: 防御准备

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 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.
View Code

 

posted @ 2016-12-03 23:03  OldJang  阅读(422)  评论(0编辑  收藏  举报