CF853B Jury Meeting(dp)

把航班按出发时间从小到大排序。从前往后扫,求出dp[i]表示i时刻全都已出发的最小花费(i时刻全部已出发,也就是说可选航班是一个时间均小于i的前缀,在这些航班中选择n个人的最小花费,具体处理见代码)。类似的,从后往前扫,求出dp1[i]表示i时刻开始走,全部返回的最小花费(也就是说可选航班是一个时间均大于i的后缀)。然后枚举i时刻全部出发,则i+k+1时刻开始返回,更新答案。

#include <bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
#define ll long long
#define inf 1LL<<60
#define N 1000005
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,k,mn[N],T=0;//dp1[i] i时刻回所有人的最小花费
ll dp[N],dp1[N];//dp[i] i时刻出发所有人的最小花费。
struct node{
    int d,s,t,v;
}a[N];
inline bool cmp(node x,node y){return x.d<y.d;}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();k=read();
    for(int i=1;i<=m;++i)
        a[i].d=read(),a[i].s=read(),a[i].t=read(),a[i].v=read(),T=max(T,a[i].d);
    sort(a+1,a+m+1,cmp);int tot=0;ll sum=0;
    memset(mn,0,sizeof(mn));
    for(int i=1;i<=T;++i) dp[i]=inf;
    for(int i=1;i<=m;++i){
        if(a[i].s==0) continue;
        if(mn[a[i].s]==0) mn[a[i].s]=a[i].v,tot++,sum+=a[i].v;
        else if(a[i].v<mn[a[i].s]) sum+=a[i].v-mn[a[i].s],mn[a[i].s]=a[i].v;
        if(tot==n) dp[a[i].d]=sum;
    }int s=1;
    while(dp[s]==inf&&s<=T) ++s;
    if(s>T){puts("-1");return 0;}
    for(int i=s+1;i<=T;++i) dp[i]=min(dp[i],dp[i-1]);
    for(int i=1;i<=T;++i) dp1[i]=inf;memset(mn,0,sizeof(mn));
    tot=0;sum=0;
    for(int i=m;i>=1;--i){
        if(a[i].t==0) continue;
        if(mn[a[i].t]==0) mn[a[i].t]=a[i].v,tot++,sum+=a[i].v;
        else if(a[i].v<mn[a[i].t]) sum+=a[i].v-mn[a[i].t],mn[a[i].t]=a[i].v;
        if(tot==n) dp1[a[i].d]=sum;
    }s=T;
    while(dp1[s]==inf&&s>=1) --s;
    if(s<1){puts("-1");return 0;}
    for(int i=s-1;i>=1;--i) dp1[i]=min(dp1[i],dp1[i+1]);
    ll ans=inf;
    for(int i=1;i+k+1<=T;++i){
        if(dp[i]==inf||dp1[i+k+1]==inf) continue;
        ans=min(ans,dp[i]+dp1[i+k+1]);
    }
    if(ans==inf) puts("-1");
    else printf("%I64d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值