题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1010
学习斜率dp的话请翻看我的 dp斜率优化小计
递推公式:f[i]=min(f[j]+(i-j-1+sum[i]-sum[j]-L)^2) , j<i
令g[i]=sum[i]+i, c=L+1
有f[i]=min(f[j]+(g[i]-g[j]-L)^2), j<i
展开,化成f[i]=min(-a[i]*x[j]+y[j])+w[i]形式有:
a[i]=2*g[i]
x[j]=g[j]
y[j]=f[j]+g[j]^2+2*g[j]*c
可以看出,a[i]与(x[j], y[j])均为增序列
那么用单调队列维护凸包就好了
1 /* 2 * Problem: BZOJ 1010 3 * Author: SHJWUDP 4 * Created Time: 2015/4/28 星期二 14:09:04 5 * File Name: 233.cpp 6 * State: Accepted 7 * Memo: 斜率优化dp 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 14 using namespace std; 15 16 typedef long long int64; 17 typedef unsigned long long int65; 18 19 const int MaxA=5e4+7; 20 21 int N, L; 22 int C[MaxA]; 23 int64 sum[MaxA], g[MaxA]; 24 int64 f[MaxA]; 25 int deque[MaxA]; 26 inline int64 getDX(int i, int j) { 27 return g[i]-g[j]; 28 } 29 inline int64 getDY(int i, int j) { 30 return (f[i]+g[i]*g[i]+2*(L+1)*g[i])-(f[j]+g[j]*g[j]+2*(L+1)*g[j]); 31 } 32 inline int64 cal(int i, int j) { 33 return f[j]+(g[i]-g[j]-(L+1))*(g[i]-g[j]-(L+1)); 34 } 35 void solve() { 36 f[0]=0; 37 int front=0, tail=0; 38 deque[tail++]=0; 39 for(int i=1; i<=N; i++) { 40 //如果单调队列中第后一个比前一个更优,那么舍弃前一个 41 while(front+1<tail && cal(i, deque[front+1])<=cal(i, deque[front])) front++; 42 f[i]=cal(i, deque[front]); 43 //维护下凸包 44 while(front+1<tail && 45 getDY(i, deque[tail-1])*getDX(deque[tail-1], deque[tail-2]) 46 <= getDY(deque[tail-1], deque[tail-2])*getDX(i, deque[tail-1])) tail--; 47 deque[tail++]=i; 48 } 49 printf("%lld\n", f[N]); 50 } 51 int main() { 52 #ifndef ONLINE_JUDGE 53 freopen("in", "r", stdin); 54 //freopen("out", "w", stdout); 55 #endif 56 while(~scanf("%d%d", &N, &L)) { 57 sum[0]=0; 58 for(int i=1; i<=N; i++) { 59 scanf("%d", &C[i]); 60 sum[i]=sum[i-1]+C[i]; 61 g[i]=sum[i]+i; 62 } 63 solve(); 64 } 65 return 0; 66 }