BZOJ3156 防御准备
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3156
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
斜率优化DP
注意这道题顺序是倒着的
交了好多次都WA,查明原因是把一个名为 calc 的函数的类型打成了 int,本来应该是 long long
从教主的代码中得到启示,要将方程化为适当的形式,以“换元”的方法增强代码的易读性。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #define rep(i,l,r) for(int i=l; i<=r; i++) 7 #define clr(x,y) memset(x,y,sizeof(x)) 8 #define travel(x) for(Edge *p=last[x]; p; p=p->pre) 9 using namespace std; 10 typedef long long ll; 11 const int maxn = 1000010; 12 ll n,m,head,tail,a[maxn],f[maxn],q[maxn]; 13 inline ll read(){ 14 ll ans = 0, f = 1; 15 char c = getchar(); 16 for(; !isdigit(c); c = getchar()) 17 if (c == '-') f = -1; 18 for(; isdigit(c); c = getchar()) 19 ans = ans * 10 + c - '0'; 20 return ans * f; 21 } 22 inline ll calc(ll x){ 23 return (f[x] << 1) + x * x; 24 } 25 int main(){ 26 n = read(); 27 rep(i,1,n) a[i] = read(); a[0] = 0; 28 f[n] = a[n]; head = 0; tail = -1; 29 q[++tail] = n; 30 for(int i=n-1; i>=0; i--){ 31 while (head < tail && calc(q[head]) - calc(q[head+1]) >= (q[head] - q[head+1]) * (i<<1|1)) head++; 32 int j = q[head]; 33 f[i] = f[j] + a[i] + (((j-i)*(j-i-1)) >> 1); 34 while (head < tail && (calc(q[tail-1]) - calc(q[tail])) * (q[tail] - i) <= (calc(q[tail]) - calc(i)) * (q[tail-1] - q[tail])) tail--; 35 q[++tail] = i; 36 } 37 printf("%lld\n",f[0]); 38 return 0; 39 }