P2120

题目传送门
这是道非常经典的斜率优化

感觉非常适合像我一样的初学者练习

Solution

dp,首先定义状态

\(dp_{i,j}\)表示在i位置是选择建仓库(0)还是向下运(1)

这样容易写出转移方程式

\(dp_{i,1}=min(dp_{i,1},dp_{j,0}+sum_i-sum_j-(x_i-x_j)*p_j)\)

\(dp_{i,0}=min(dp_{i-1,0},dp_{i,1})+c_i\)

提交
看看数据范围\(1 \leq n \leq 1e6~O(N^2)\)明显TLE

怎么办呢

当然是斜率优化

将转移方程式化简一下
\(dp_{j,0}-sum_j+x_j*p_j=x_i*p_j+dp_{i,1}-sum_i\)

\(dp_{j,0}-sum_j+x_j*p_j=y\) \(p_j\)\(x\) 剩下那一堆为\(b\)

那么就可以轻松求解斜率啦

最后用单调队列维护下凸壳

这样就将时间复杂度降到\(O(N)\)

上代码(含有注释)

#include<bits/stdc++.h>
#define int long long
#define double long double//避免精度下降 
using namespace std;

const int N = 1e6+5;
int n,x[N],p[N],c[N];
int q[N];
//工厂 i 距离工厂 11 的距离 x
//工厂 i 目前已有成品数量 p
int sum[N];
int dp[N][2];//0 buld 1 move

inline double solve(int i,int j)
{
	//dp[j][0]-sum[j]+x[j]*p[j]=dp[i][1]-sum[i]+x[i]*p[j]
	int y1=dp[i][0]-sum[i]+x[i]*p[i];
	int y2=dp[j][0]-sum[j]+x[j]*p[j];
	int x1=p[i],x2=p[j];
	return 1.0*(y1-y2)/(x1-x2);
   //求解斜率
}

inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}// 日常快读 

signed main()
{
    n=read();
    for(register int i=1;i<=n;i++)
    {
    	x[i]=read(),p[i]=read(),c[i]=read();
    	p[i]+=p[i-1];
    	sum[i]=sum[i-1]+(x[i]-x[i-1])*(p[i-1]);
    	//将所有东西运到i的总花费(不考虑建造仓库) 
	}
	int head=1,tail=1;
	for(register int i=1;i<=n;i++)
	{
		/*
		dp[i][1]=sum[i];//全部运 
		for(register int j=1;j<i;j++)//在j处建造仓库 
		{
			dp[i][1]=min(dp[i][1],dp[j][0]+sum[i]-sum[j]-(x[i]-x[j])*(p[j]));
			//全部运到i-全部运到j==将全部从j运到i(多算x[j]
		}
		dp[i][0]=min(dp[i-1][0],dp[i][1])+c[i];
		*/
		//dp[i][1]-sum[i]=-x[i]*p[j]+dp[j][0]-sum[j]+x[j]*p[j]
		//dp[j][0]-sum[j]+x[j]*p[j]=x[i]*p[j]+dp[i][1]-sum[i]
		while(head<tail&&solve(q[head+1],q[head])<x[i]) head++;
		// 若最小斜率小于与直线相切的斜率 入队
		int j=q[head];
		dp[i][1]=dp[j][0]+sum[i]-sum[j]-(x[i]-x[j])*p[j];
		dp[i][0]=min(dp[i-1][0],dp[i][1])+c[i];
		while(head<tail&&solve(i,q[tail])<solve(q[tail],q[tail-1])) tail--;
		q[++tail]=i;
		// 出队 
	}
	printf("%d",min(dp[n][1]+c[n],dp[n][0]));
	//最终答案
    return 0;
}
// 完美AC 
// 70行 

AC这道题后,建议去看看玩具装箱

posted @ 2022-05-08 09:26  starrylasky  阅读(27)  评论(0)    收藏  举报