[NOI2019]回家路线routeDAY1T1【斜率优化dp】

[传送门](https://loj.ac/problem/3156)
=
-----
SOL
=
题意:长度为n的路径上有m辆车,每辆车$i$有起点$x_{i}$, 终点$y_{i}$, 上车时间$p_{i}$, 下车时间$q_{i}$ 。问从$1$点上车,通过换乘到达$n$号点的最小代价。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190716165620585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMDQwNjU1,size_16,color_FFFFFF,t_70)
注意:只能在下车点上车。
----

**一、考虑dp**
虽然不满足$x_{i}<y_{i}$,但是有时间限制,且$p_{i}<q_{i}$,所以不会有后效性。
不难发现状态总量为$O(m)$,有$dp[i]$ 表示坐第$i$辆车,在$q_{i}$时间到达$y_{i}$的最小代价
(总时间$q_{s_{k}}$最后加入答案)
$$dp[i]=min(dp[j]+A*(p_{i}-q_{j})*(p_{i}-q_{j})+B*(p_{i}-q_{j})+C)$$
且满足$x_{i}=y_{j}$,$p_{i}>=q_{j}$。

对方程变形
$$2*A*p_{i} * q_{j}+dp[i]-(A*p_{i}*p_{i}+B*p_{i}+C)=dp[j]+A*q_{j}*q_{j}-B*q_{j}$$
对于决策点对$(x,y)$,有$x=q_{j}$,$y=dp[j]+A*q_{j}*q_{j}-B*q_{j}$。
---
**二、考虑决策集合的维护。**
对于每辆车的起点终点$u,v$,维护$t$时间下的凸包集合。集合内决策点满足$q_{i}<=t$.
法一:$O(m* log m)$
 用$set$装下$u,v$的待加入点,在讨论当前$x_{i}$时,先按$q_{i}$从小到大加入。
 
法二:$O(m)$
桶排排序
将决策点$j$在$q_{j}$时间,加入$y[j]$的凸包中。对于当前点$i$,询问$p_{i}$时间下$x_{i}$的凸包。
-----
CODE
=
$O(m)$
```cpp
//O(m)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
 int num=0,f=1;char c=gc;
 for(;!isdigit(c);c=gc)if(c=='-')f=-1;
 for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
 return num*f;
}
cs int N=2e5+10;
struct pi{
 ll x,y;
 int id;
};
int p[N],q[N],x[N],y[N],n,m,A,B,C,head[N];
queue<int> res[3100];
vector<pi> que[N];
vector<int> d[3200];
ll dp[N],ans=1e18;
inline db slope(cs pi &a,cs pi &b){
 return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i){
 int pos=y[i];
 pi now=(pi){q[i],dp[i]+A*q[i]*q[i]-B*q[i],i};
 while(que[pos].size()-head[pos]>=2){
  int len=que[pos].size();
  if(slope(que[pos][len-1],que[pos][len-2])<slope(que[pos][len-2],now))break;
  que[pos].pop_back();
 }
 que[pos].push_back(now);
}
inline void getout(cs db &slp,cs int &pos){
 while(que[pos].size()-head[pos]>=2){
  if(slope(que[pos][head[pos]],que[pos][head[pos]+1])>slp)return;
  ++head[pos];
 }
}
signed main(){
 n=in,m=in,A=in,B=in,C=in;
 for(rint i=1;i<=m;++i){
  x[i]=in,y[i]=in,p[i]=in,q[i]=in;
 }
 for(rint i=1;i<=m;++i)d[p[i]].push_back(i);
 que[1].push_back((pi){0,0,0}); 
 int i;
 for(rint t=0;t<=3000;++t){
  while(!res[t].empty())getin(res[t].front()),res[t].pop();
  int len=d[t].size();
  for(rint tmp=0;tmp<len;++tmp){
   int i=d[t][tmp];
   int pos=x[i];
   if(que[pos].size()<=head[pos])continue;
   db slp=2.0*A*p[i];
   getout(slp,pos);
   int j=que[pos][head[pos]].id;
   dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
   res[q[i]].push(i);
   if(y[i]==n){
    ans=min(ans,dp[i]+q[i]);
   }
  }
 }
 cout<<ans;
 return 0;
}
```
-----
$O(m*logm)$
```cpp
//O(m*logm)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
 int num=0,f=1;char c=gc;
 for(;!isdigit(c);c=gc)if(c=='-')f=-1;
 for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
 return num*f;
}
cs int N=2e5+10;
struct pi{
 ll x,y;
 int id;
};
typedef pair<int,int> pa;
int ord[N],p[N],q[N],x[N],y[N],n,m,A,B,C;
set<pa> res[N];
deque<pi> que[N];
ll dp[N],ans=1e18;
bool cmp(int a,int b){return p[a]<p[b];}
inline db slope(cs pi &a,cs pi &b){
 return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i,cs int &pos){
 //cout<<"getin\n"<<i<<' '<<pos<<'\n';
 while(!res[pos].empty()){
  pa t=*res[pos].begin();
  if(t.fi>p[i])break;
  pi now=(pi){t.fi,dp[t.se]+A*t.fi*t.fi-B*t.fi,t.se};
  while(que[pos].size()>=2){
   pi a=que[pos].back();que[pos].pop_back();
   pi b=que[pos].back();
   if(slope(b,a)<slope(b,now)){
    que[pos].push_back(a);
    break; 
   }
  }
  //cout<<now.x<<' '<<now.y<<' '<<now.id<<'\n';
  que[pos].push_back(now);
  res[pos].erase(t);
 }
// cout<<"siz: "<<que[pos].size()<<'\n';
}
inline void getout(cs db &slp,cs int &pos){
// cout<<"slp:"<<slp<<'\n';
 while(que[pos].size()>=2){
  pi a=que[pos].front();que[pos].pop_front();
  pi b=que[pos].front();
 // cout<<"slope:"<<slope(b,a)<<'\n';
  if(slope(b,a)>slp){
   que[pos].push_front(a);
   return; 
  }
 }
}
signed main(){
// freopen("data.in","r",stdin);
 n=in,m=in,A=in,B=in,C=in;
 //sf("%d%d%d%d%d",&n,&m,&A,&B,&C);
 for(rint i=1;i<=m;++i){
  x[i]=in,y[i]=in,p[i]=in,q[i]=in;
  //sf("%d%d%d%d",&x[i],&y[i],&p[i],&q[i]);
  ord[i]=i;
 }
// random_shuffle(ord+1,ord+m+1);
 sort(ord+1,ord+m+1,cmp);
 que[1].push_back((pi){0,0,0});
 for(rint o=1;o<=m;++o){
  int i=ord[o];
  int pos=x[i];
 // cout<<"turn: "<<o<<"\n";
  getin(i,pos);
  if(que[pos].empty())continue;
  db slp=2.0*A*p[i];
  getout(slp,pos);
  int j=que[pos].front().id;
  dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
 // cout<<q[i]<<' '<<y[i]<<' '<<dp[q[i]][y[i]]<<'\n';
  res[y[i]].insert(make_pair(q[i],i));
  if(res[y[i]].size()>50000)getin(i,y[i]);
  if(y[i]==n){
   ans=min(ans,dp[i]+q[i]);
  }
 }
 cout<<ans;
 return 0;
}
```
 

猜你喜欢

转载自www.cnblogs.com/rhjoi/p/11355328.html