详见http://www.cnblogs.com/xiaolongchase/archive/2012/02/10/2344769.html

1 /* 2 dp+斜率优化 3 题意:给定一些点,把这些点分成某些行 4 对于分成同一行的点的代价为:( sigma(x)*sigma(x)+m ) 5 求最小的代价 6 dp[ i ] = min( dp[ j ]+(sum[i]-sum[j])^2+m ) (其中j<=i)//以第i个点为末尾的最小代价 7 8 首先对于任意的j,k( j<k<=i ) 9 如果说k的决策由于j,那么可得到dp[ k ]+(sum[i]-sum[k])^2+m<dp[j]+(sum[i]-sum[j])^2+m 10 移项可得 { dp[j]+sum[j]^2-(dp[k]+sum(k)^2) }/( sum[j]-sum[k] ) < 2*sum[i]; 11 再令 solve( j,k ) = { dp[j]+sum[j]^2-(dp[k]+sum(k)^2) }/( sum[j]-sum[k] ); 12 那么也就是说如果决策 k 优于决策 j ,就能得到 solve( j,k )<2*sum[i]; 13 ->->->->->->->这就是结论1 14 15 对于任意的 j,k,p ( j<k<p ),有solve( j,k ),solve( k,p ); 16 IF( solve( j,k )>solve( k,p ) ) { 17 if( solve( k,p )<2*sum[i] ) p优于k,则k是无用的决策 18 if( solve( k,p )>2*sum[i] ) 能推出solve( j,k )>2*sum[i],也就是说k不比j优,同样的k是无用的决策,可以去掉 19 so,只要满足这个大的IF条件,那么k就是无用的决策 20 21 */ 22 #include<stdio.h> 23 #include<string.h> 24 typedef long long int64; 25 const int maxn = 500005; 26 const int inf = 99999999; 27 28 int64 sum[ maxn ]; 29 int64 dp[ maxn ]; 30 int que[ maxn ]; 31 32 int solve( int j,int k ){ 33 if( sum[j]==sum[k] ){//防止除0 34 if( dp[j]>dp[k] ) return -1;//这个要由最原始的solve推出 35 else return inf; 36 } 37 return (dp[j]-dp[k]+sum[j]*sum[j]-sum[k]*sum[k])/(sum[j]-sum[k]); 38 } 39 40 int main(){ 41 int n,m; 42 while( scanf("%d%d",&n,&m)!=EOF ){ 43 memset( dp,0,sizeof( dp ) ); 44 //memset( que,0,sizeof( que )); 45 sum[ 0 ] = 0; 46 for( int i=1;i<=n;i++ ){ 47 scanf("%lld",&sum[i]); 48 sum[i] += sum[i-1]; 49 } 50 int head,tail; 51 head = tail = 0; 52 for( int i=1;i<=n;i++ ){ 53 while( head<tail && solve( que[ head ],que[ head+1 ] )<2*sum[i] ) 54 head++; 55 //结论1 56 dp[ i ] = dp[ que[ head ] ]+(sum[que[head]]-sum[i])*(sum[que[head]]-sum[i])+m; 57 while( head<tail && solve( que[ tail-1 ],que[ tail ] )>solve( que[ tail ],i ) ) 58 tail--; 59 //结论2 60 tail++; 61 que[ tail ] = i; 62 } 63 printf("%lld\n",dp[n]); 64 } 65 return 0; 66 } 67