题目大意:将n个升序数字序列,分成几组连续的序列 ,每一组的所得值,等于最右边的num2减去最左边 的num1,的平方+c即(numi-numj)^2+c
解题报告 人:GHQ(SpringWater)
分析可得:(dp[j2]-dp[j1]+num[j2+1]*num[j2+1]-num[j1+1]*num[j1+1])/(2(num[j2+1]-num[j1+1]))《=num[i]时,j2比j1更优,可知这是一个凹曲线斜率优化;
i<j<k时且k(i,j)>=k(j,k)时,那么j是可以去掉的。
1.当 k(j,k)《=num[i]时,j没 k优,可去 j
2.当 k(j,k)>=num[i]时,则k(i,j)》=num[i],i比j优秀,可去j!
自己默思:1,:为什么当前队列左边相邻的k(l,l+1) 第一个满足>num[i]时,即l比l+1优,则l比右边的所有 都优,因为l和右边的组合斜率是增加的,l+1同样优于l+2,
由传递性可得,第一次l为最优,
2:为什么当前i总用和相邻的(r-1,r)和(r,i)比较即可确定是否删除r,因为当k(r,i)>=k(r,r-1)则k(r,i)大于在队列里所有任意 组合 的 斜率!能确保 k(r,i)是最大的 斜率。
也就 保证了,斜率递增!
当>=num[i]时为凸曲线斜率优化!
hdu4258 #include<stdio.h> #define MAXN 1000005 int que[10000]; __int64 num[MAXN],dp[MAXN]; double k(int j1,int j2) { return (double)(dp[j2]-dp[j1]+num[j2+1]*num[j2+1]-num[j1+1]*num[j1+1])/(double)(2.0*(num[j2+1]-num[j1+1])); } int main() { int n, i, l, r; __int64 c; while(scanf("%d%I64d",&n,&c) && (n || c)) { for(i = 1; i <= n; i++) scanf("%I64d",&num[i]); dp[0] = 0; dp[1]=c; que[l = 0] = 0; que[r = 1] = 1; for(i = 2; i <= n; i++) { while((l < r)&&k(que[l],que[l+1])<=(double)num[i])++l; dp[i]=dp[que[l]]+c+(num[i]-num[que[l]+1])*(num[i]-num[que[l]+1]); while((l < r)&&k(que[r],i)<=k(que[r-1],que[r]))--r; que[++r] = i; } printf("%I64d\n",dp[n]); } return 0; }