zoukankan      html  css  js  c++  java
  • P5468 [NOI2019] 回家路线

    P5468 [NOI2019] 回家路线

    斜率优化入门(指我写的东西而不是这道题)

    题意

    (n) 个节点,有 (m) 趟列车,车 (i)(p_i) 时刻至 (q_i) 时刻从 (x_i) 地到 (y_i) 地。猫猫需要只坐列车从 (1) 节点到达 (n) 节点。

    设猫猫在一个地方等待的时间为 (t),那么代价为 (At^2+Bt+C),其中 (A B C) 为给定非负常数,总代价为所有代价总和与到达时间的和。求最小代价。

    思路

    (f_i) 为走 (i) 趟列车前的最小代价,有转移方程:

    [f_i=min_{y_j=x_iland q_jleq q_i}(f_j+A(p_i-q_j)^2+B(p_i-q_j)+C) ]

    最终代价即为:

    [min f_i+q_i ]

    对于第一个方程,不考虑其他限制,即为找到最优的 (j) 更新 (i),有:

    [egin{aligned} f_i&=f_j+A(p_i-q_j)^2+B(p_i-q_j)+C\ f_i&=f_j+Ap_i^2+Aq_j^2-2Ap_iq_j+Bp_i-Bq_j+C\ f_j+Aq_j^2-Bq_j&=2Ap_iq_j+f_i-Ap_i^2-Bp_i-C end{aligned} ]

    对于已经更新过的 (j)(f_j+Aq_j^2-Bq_j) 是已知的。后半部分 (f_i-Ap_i^2-Bp_i-C) 只有 (f_i) 是未知的,也是我们要最优化的。

    那么我们可以将上式看做 (y=kx+b) 的形式,其中

    [egin{aligned} &y=f_j+Aq_j^2-Bq_j\ &x=q_j\ &k=2Ap_i\ &b=f_i-Ap_i^2-Bp_i-C end{aligned} ]

    (常数其实可以属于任意一个位置,上述只是举例)

    那么我们可以将所有可以转移到的 (j) 看做一个二维平面上的点,每次更新 (f_i) 实际是对一个斜率找出经过其中一个点得到的最优的 (b)。那么显然只会选到前者构成的凸包上的点。很多题查询的斜率都是单调的,而且之后在凸包后方插入新的点,于是维护凸包的数组就变成了单调队列。否则的话,就是动态维护凸包并在凸包上二分。

    对于这道题,最优指最小,那么我们维护的是下凸包。

    斜率优化的部分已经完了。考虑加入 (y_j=x_i and q_jleq p_i) 的限制怎么做。对于第一个限制,发现不同点互不影响,那么我们对每个点开一个单调队列,对于一个列车在它的 (x) 位置查询就好了。对于第二个限制,我们将所有列车按照 (p) 排序然后枚举时间,那么对于上面更新完的列车先不插入队列,当枚举时间到 (p) 的时候再将其插入即可。这样就能满足所有限制,并且保证查询的斜率单调递增。

    代码

    好像不会炸 long long 的样子。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int w=0,x=0;char c=getchar();
    	while(!isdigit(c))w|=c=='-',c=getchar();
    	while(isdigit(c))x=x*10+(c^48),c=getchar();
    	return w?-x:x;
    }
    namespace star
    {
    	const int maxn=1e6+10;
    	int n,T,m,A,B,C,st[maxn],ed[maxn],p[maxn],q[maxn],hd[maxn],tl[maxn];
    	long long f[maxn],x[maxn],y[maxn],ans=0x3f3f3f3f3f3f3f3f;
    	vector<int> V[maxn],G[maxn],que[maxn];
    	inline void work(){
    		n=read(),m=read(),A=read(),B=read(),C=read();
    		for(int i=1;i<=m;i++) st[i]=read(),ed[i]=read(),p[i]=read(),q[i]=read(),T=max(T,q[i]),G[p[i]].push_back(i);
    		for(int i=1;i<=n;i++) hd[i]=0,tl[i]=-1;
    		for(int t=0;t<=T;t++){
    			for(auto i:V[t]){
    				int e=ed[i];
    				while(hd[e]<tl[e] and 1ll*(y[que[e][tl[e]]]-y[que[e][tl[e]-1]])*(x[i]-x[que[e][tl[e]]])>=1ll*(y[i]-y[que[e][tl[e]]])*(x[que[e][tl[e]]]-x[que[e][tl[e]-1]])) --tl[e];
    				if(++tl[e]==que[e].size()) que[e].push_back(i);
    					else que[e][tl[e]]=i;
    			}
    			for(auto i:G[t]){
    				int e=st[i];
    				while(hd[e]<tl[e] and (y[que[e][hd[e]+1]]-y[que[e][hd[e]]])<2ll*A*p[i]*(x[que[e][hd[e]+1]]-x[que[e][hd[e]]])) ++hd[e];
    				if(hd[e]>tl[e] and st[i]!=1) continue;
    				int j=st[i]==1 and hd[e]>tl[e]?0:que[e][hd[e]];
    				f[i]=f[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
    				x[i]=q[i],y[i]=f[i]+1ll*A*q[i]*q[i]-1ll*B*q[i];
    				V[q[i]].push_back(i);
    				if(ed[i]==n) ans=min(ans,f[i]+q[i]);
    			}
    		}
    		printf("%lld
    ",ans);
    	}
    }
    signed main(){
    	star::work();
    	return 0;
    }
    
  • 相关阅读:
    状态压缩 + 暴力 HDOJ 4770 Lights Against Dudely
    简单几何(推公式) UVA 11646 Athletics Track
    简单几何(四边形形状) UVA 11800 Determine the Shape
    简单几何(求交点) UVA 11437 Triangle Fun
    计算几何模板
    简单几何(相对运动距离最值) UVA 11796 Dog Distance
    简单几何(求划分区域) LA 3263 That Nice Euler Circuit
    覆盖的面积 HDU
    Desert King 最小比率生成树 (好题)
    约会安排 (区间合并)毒瘤题
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/14846645.html
Copyright © 2011-2022 走看看