[NOI2019] 回家路线

题意:

给定一张n个点m条边的有向图,每条边代表一趟车,有发车时间$p_i$和到站时间$q_i$。

现在你要从点1坐车到点n,对于一次在点u的换乘,若你在时刻q到达u,在时刻p离开u,则会产生$A(p-q)^{2}+B(p-q)+C$的不满意度。

若你最后在时刻p到达点n还会产生p的不满意度,求从1到n最小的不满意度。

$nleq 10^{5},mleq 2times 10^{5},0leq p_i < q_i leq 10^{3}$。

 

题解:

挺水的一道题,听说场上写个$O(mt)$的分层图最短路就能过?给爷整笑了

显然可以设$dp(i,j)$表示第i个时刻在第j个点的最小不满意度,转移类似于spfa,复杂度$O(m^{2}t)$。

仔细考虑一下发现只有$i=q_k$的状态有用,所以总状态数是$O(m)$的,复杂度$O(m^{2})$。

再考虑一下,这个转移显然是个斜率优化的形式,我们只需要对每个点动态建凸包即可做到$O(mlog{m})$。

显然不能按拓扑序转移(时间混乱),考虑直接按时间转移。

注意到每个状态的dp值都是在一条边上算出来的,于是原图就可以丢掉了。

把每条边挂到$p_i$和$q_i$上,每个dp值在p处算出来,在q处插入凸包。

复杂度$O(mlog{m})$。过掉这题总共花了大概2h,我没希望了

 

套路:

  • 搭车问题:以时间为第一关键字转移。

 

代码:

[NOI2019] 回家路线

#include<bits/stdc++.h>
#define maxn 200005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
#define rint register ll
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
ll n,m,A,B,C;
struct node{ll x,y;};
struct edge{ll u,v,p,q,dp;}E[maxm];
vector<ll> vec[maxn];
vector<node> st[maxn];

inline ll read(){
    ll x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline void ins(ll u,node c){
    while(st[u].size()>1){
        ll t=st[u].size()-1; node a=st[u][t-1],b=st[u][t];
        if((b.y-a.y)*(c.x-b.x)>=(c.y-b.y)*(b.x-a.x)) st[u].pop_back();
        else break;
    }
    st[u].push_back(c);
}
inline node qry(ll u,ll k){
    if(!st[u].size()) return (node){-1,-1};
    ll l=1,r=st[u].size()-1,res=0;
    while(l<=r){
        ll mid=l+r>>1;
        node a=st[u][mid-1],b=st[u][mid];
        if(b.y-a.y<=(b.x-a.x)*k) res=mid,l=mid+1;
        else r=mid-1;
    }
    return st[u][res];
}
inline ll getdp(node a){return a.y-A*a.x*a.x+B*a.x;}

int main(){
    n=read(),m=read(),A=read(),B=read(),C=read();
    for(ll i=1;i<=m;i++){
        E[i].u=read(),E[i].v=read(),E[i].p=read(),E[i].q=read(),E[i].dp=1ll<<62;
        vec[E[i].p].push_back(i),vec[E[i].q].push_back(i);
    }
    ins(1,(node){0,0}); ll ans=1ll<<62;
    for(ll tim=0;tim<=1000;tim++){
        if(!vec[tim].size()) continue;
        for(ll i=0;i<vec[tim].size();i++){
            edge e=E[vec[tim][i]];
            if(e.q==tim && e.dp!=(1ll<<62)) 
                ins(e.v,(node){e.q,e.dp+A*e.q*e.q-B*e.q}); 
        }
        for(ll i=0;i<vec[tim].size();i++){
            edge e=E[vec[tim][i]];
            if(e.p==tim){
                node a=qry(e.u,2ll*A*e.p); 
                if(a.x==-1) continue; ll x=e.p-a.x;
                E[vec[tim][i]].dp=getdp(a)+A*x*x+B*x+C;
                if(e.v==n) ans=min(ans,E[vec[tim][i]].dp+e.q);
            }
        }
    }
    printf("%lldn",ans);
    return 0;
}

回家路线

 

原文链接: https://www.cnblogs.com/YSFAC/p/13336055.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    [NOI2019] 回家路线

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/368202

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午6:16
下一篇 2023年3月2日 下午6:17

相关推荐