斜率dp类似这种情况 dp[i]=dp[j]+f(i,j) 或者简单一点 dp[i]=dp[j]+a[i]+a[j]这种,i是1e5级别的;
1:求出状态转移方程
2:求出 y,x,k 其中y中要不含除x以外的变量
3:判断是维护下凸包还是上凸包,具体判断方法为在队头能取到题目要求的截距最值;
技巧:
1:当题目不满足连续的性质时,要进行排序等操作,使他们满足连续取才是最优的这个性质
2:当a[i]可以为负数的时候,要二分找斜率
3:当题目要求要倒着dp的时候(j从n到1) 如果x是单调递减的,那么可以用-x做x -k做k 这样方便计算
4:一般情况下double不会被卡(用cf的一个题目做了实验,没被卡)
题意:给一个n个数的数组,可以分成若干个组,假设有一个组有k个元素(连续),那么就要花费这k个数和的平方,求将这n个数都分组最少要花费多少
思路:大家都会的状态转移 f[i]=f[j]+(sum[i]-sum[j])^2+m 1<=j&&j
化简:f[j]+sum[j]^2=2*sum[i]sum[j]+dp[i]-sum[i]*sum[i]-m;这个是以sum[j]为横坐标,f[j]+sum[j]^2为纵坐标 2*sum[i]为斜率(大于0),dp[i]-sum[i]^2-m为截距的方程,求满足一个j,使这个方程截距最小;然后就斜率优化一下 ;斜率优化的一个入门题目;但是这个题目有一个坑就是 在维护下凸壳的时候必须删掉重复的点(这个题目c[i]可以等于0),如果没有删除就维护不了下凸壳(不信可以模拟一下)也不能用double做这个题目,因为分母可能为0;就像维护凸包的时候也要去掉重复的点一样,还有就是要注意求斜率的时候,乘以负数和要变号的情况;
题意:https://vjudge.net/problem/HYSBZ-1010
思路:很容易求出状态转移方程 dp[x]+(a-sum[x]-x)*(a-sum[x]-x) 其中 a=sum[i]+i-1-m; x
化简 dp[x]+(LL)x*x+(sum[x]+2*x)*sum[x]=2a*(sum[x]+x)+dp[i]; 板子题要注意 y只能含有自变量x不能含有其它数,含有其它数当那个数变了,就不是下凸壳了 这个题目y不能为 dp[x]+(LL)x*x+(sum[x]+2*x-2*a)*sum[x];
题意:https://vjudge.net/problem/HYSBZ-1911
思路:很容易求出状态转移方程 dp[i]=dp[x]+a*g*g+b*g+c; 其中g=(sum[i]-sum[x]) 然后求出y,x,k 这个题目不一样的是求最小值但是维护的是上凸包,因为斜率是负的;
题意:https://vjudge.net/problem/HYSBZ-3675
思路:将一个序列分成m+1段 很好想到dp方程 dp[i][j]=dp[x][j-1]+(sum[i]-sum[x])*(sum[n]-sum[i]);化简一下,就可以到了;
需要注意的是这个方程有二维,需要将j放在for循环的第一层,注意单调队列里面的决策点要合法;
题意:https://vjudge.net/problem/HYSBZ-1597
思路:发现这个题目连续的取不一定是最优的,但是要用斜率dp解决要是连续的取,可以先考虑按x排序,那么就会发现可以将一些点合并 当i>j 时且 b[i]>b[j]时这样就可以合并这二个相邻的元素,那么这个时候连续的取明显是最优的,写出状态转移方程
dp[i]=dp[x]+a[i]*b[x+1]; 化简 dp[x]=-a[i]*b[x+1]+dp[i] 发现b[x+1]是递减的,刚好b[x+1]前面有个负号,那么y=dp[x] 单调递增,
x=-b[x+1]单调递增,a[i]单调递增,那么套板子就行了;
题意:给一个数组,这个数组的权值为, 现在有一个操作将一个数提出来,随便插哪个地方(可以插原来的地方),求操作后数组的权值最大;
思路:假设将i这个位置的数往左边插 那么很容易写出状态方程 all+(sum[i-1]-sum[j-1])-(i-j)*a[i]; 其中j<=i;
当然也可以往右边插 all+(j-i)*a[i]-(sum[j]-sum[i]); 其中j>=i 每次动i这个位置是有原因的,只有这样才能更方便的用斜率优化
当然k=a[i]可以为正数和负数 就要二分了。还有一个技巧就是当反正dp的时候(i从n到1) 其中的斜率方程的x单调递减,可以用
-x 为x,这样就可以避免一些麻烦;