bzoj 1010 斜率优化DP
我的第二道斜率DP。
收获:
1、假设两个位置:p<q<i,然后让某一位置优,看其满足什么性质,所谓斜率优化就是满足:
(g[q]-g[p])/(f[q]-f[p]) op h[i]
要化简成这样,必须满足f函数关于位置单调,否则op(<或>)的方向就会因为f的大小关系而变化,就没有凸的性质了。
2、斜率优化很难调试,所以当发现暴力DP和同样的方程被斜率优化了一下的答案不同时,不要去调试,直接去检查上面的各个函数是否写错或抄到代码中抄错了,
或者重推一遍。(注意决策点是否可能会重合)
1 /************************************************************** 2 Problem: 1010 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:116 ms 7 Memory:3148 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #define ln(A,B) ((B)-(A)) 12 #define maxn 50010 13 14 typedef long long lng; 15 16 struct Vector { 17 lng x, y; 18 int id; 19 Vector(){} 20 Vector( lng x, lng y, int id ) : x(x), y(y), id(id) {} 21 Vector operator-( const Vector & b ) const { 22 return Vector( x-b.x, y-b.y, -1 ); 23 } 24 lng operator&( const Vector & b ) const { 25 return x*b.y-y*b.x; 26 } 27 }; 28 typedef Vector Point; 29 30 int n, L; 31 int cost[maxn]; 32 lng g[maxn], sum[maxn]; 33 lng dp[maxn]; 34 int beg, end; 35 Point qu[maxn]; 36 37 inline lng sqr( lng a ) { 38 return a*a; 39 } 40 int main() { 41 scanf( "%d%d", &n, &L ); 42 sum[0] = 0; 43 for( int i=1; i<=n; i++ ) { 44 scanf( "%d", cost+i ); 45 sum[i] = sum[i-1]+cost[i]; 46 g[i] = sum[i]+i; 47 } 48 dp[0] = 0; 49 qu[beg=end=0] = Point( 0, 0, 0 ); 50 for( int i=1; i<=n; i++ ) { 51 while( beg<end && (qu[beg+1].y-qu[beg].y)<=(qu[beg+1].x-qu[beg].x)*2*g[i] ) 52 beg++; 53 int j = qu[beg].id; 54 55 dp[i] = dp[j]+sqr(sum[i]-sum[j]-L+i-j-1); 56 Point npt = Point( g[i], dp[i]+g[i]*g[i]+2*g[i]*(L+1), i ); 57 while( beg<end && (ln(qu[end-1],qu[end])&ln(qu[end-1],npt))<=0 ) 58 end--; 59 qu[++end] = npt; 60 61 } 62 printf( "%lld\n", dp[n] ); 63 }