[BZOJ3156] 防御准备

来源:互联网 发布:phpcms数据库配置文件 编辑:程序博客网 时间:2024/06/06 05:20

f[i]表示第i个检查站的位置建防御塔的最小花费

那么

f[i]=Min(f[j]+k=j+1i1(ik))

考虑用斜率优化

j<kkj更优,
那么可以得到

f[k]+(ik)(ik1)2f[j]+(ij)(ij1)2

化简得

2(f[k]f[j])+k2j2+kj2(kj)i

slope(k,j)=2(f[k]f[j])+k2j2+kj2(kj)

于是可以得到,弹队首的条件:满足slope(l,l+1)<=i
弹队尾的条件:满足slope(r,r1)>slope(i,r)
时间复杂度O(N)

#include <cstdio>using namespace std;template <class T>T Max (const T &a, const T &b) {return a > b ? a : b;}template <class T>T Min (const T &a, const T &b) {return a < b ? a : b;}typedef long long LL;typedef double dl;const int SN = 1000000 + 100;LL a[SN], n, f[SN];int que[SN], head, tail;void Read(LL &x) {    LL in = 0, f = 1;char  ch = getchar();    while(ch<'0' || ch>'9') {if(ch=='-') f = -1;ch = getchar();}    while(ch>='0' && ch<='9') {in = in*10+ch-'0'; ch = getchar();}    x = in*f;}LL get_up(LL i,LL j) { //i,j都要开long long     return 2*(f[i]-f[j])+i*i-j*j+i-j;}dl get_slope(LL i,LL j) {    return (double)((get_up(i,j))/(double)(i-j));}int main() {    Read(n);    for(int i = 1; i <= n; i++) Read(a[i]);    for(int i = 1; i <= n; i++) {        while(head < tail && get_slope(que[head+1],que[head])<= 2*i) head++;        f[i] = f[que[head]] + (i-que[head])*(i-que[head]-1)/2 + a[i];           while(head < tail && get_slope(i, que[tail]) <= get_slope(que[tail], que[tail-1]))           tail--;           que[++tail] = i;    }    printf("%lld\n",f[n]);    return 0;}
原创粉丝点击