1 条题解

  • 0
    @ 2025-8-24 21:51:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Ebola
    来证个定理吧!

    搬运于2025-08-24 21:51:36,当前版本为作者最后更新于2018-10-30 21:19:50,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    一道非常繁琐的贪心题,需要高超的实现技巧,否则代码会很丑

    在这里先%一下Mys_C_K大爷,他的写法实在是太优美了

    先根据给定的这些机票,处理出每种类型机票的最小花费,用哈希表保存一下(懒人用unordered_map)

    然后对于一种x与y之间的飞行,记A表示x到y的单程最小花费,B表示y到x的单程最小花费,AB表示x到y的来回最小花费,BA表示y到x的来回最小花费

    单程最小花费需要考虑往返机票反而更便宜的情况。来回最小花费需要考虑两张单程反而比一张往返便宜的情况

    然后如果AB比BA小,就优先选择x到y往返。注意到一个往返机票买了之后是可以任意时刻免费返程的,所以可以做类似括号匹配的事情,将匹配的位置打上删除标记。然后再选择y到x的往返。最后再处理x到y的单程、y到x的单程

    如果AB比BA大,那也是一样的,就把优先顺序换一下就好了。注意到这是完全一样的过程,所以如果AB比BA大,我们可以swap(A,B),swap(AB,BA),然后将x与y的意义交换一下,代码就不用再多写一遍了

    贪心的正确性显然

    #include<bits/stdc++.h>
    #define FR first
    #define SE second
    using namespace std;
    
    const int S=(1<<20)+5;
    char buf[S],*H,*T;
    inline char Get()
    {
        if(H==T) T=(H=buf)+fread(buf,1,S,stdin);
        if(H==T) return -1;return *H++;
    }
    inline int read()
    {
        int x=0;char c=Get();
        while(!isdigit(c)) c=Get();
        while(isdigit(c)) x=x*10+c-'0',c=Get();
        return x;
    }
    inline bool readc()
    {
        char c=Get();
        while(c!='O'&&c!='R') c=Get();
        return c=='R';
    }
    template<class I> inline void upmin(I &x,const I &y){if(y<x) x=y;}
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N=300010;
    struct Type
    {
        int u,v,ty;
        Type(int _u=0,int _v=0,int _ty=0):u(_u),v(_v),ty(_ty){}
        LL gethash(){return (LL)u*N*2+v*2+ty;}
    };
    
    unordered_map<LL,int> h;
    map<pii,int> idx;
    int n,m,pfm[N],d[N],cnt=0;
    vector<int> V[N];
    int stk[N];
    bool del[N];
    LL ans=0;
    
    int val(pii pr,int d)
    {
        LL tmp=Type(pr.FR,pr.SE,d).gethash();
        if(!h.count(tmp)) return INT_MAX;
        else return h[tmp];
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++) pfm[i]=read();
        int tot=read();
        for(int i=1;i<=tot;i++)
        {
            int x=read(),y=read(),z=readc(),w=read();
            if(!h.count(Type(x,y,z).gethash())) h[Type(x,y,z).gethash()]=w;
            else upmin(h[Type(x,y,z).gethash()],w);
        }
        for(int i=1;i<m;i++)
        {
            int x=pfm[i],y=pfm[i+1];
            if(x>y) swap(x,y),d[i]=1;
            if(!idx.count(pii(x,y))) idx[pii(x,y)]=++cnt;
            V[idx[pii(x,y)]].push_back(i);
        }
        for(auto mpr : idx)
        {
            if(!V[mpr.SE].size()) continue;
            pii pr=mpr.FR,ipr=pii(pr.SE,pr.FR);
            LL A=val(pr,0),B=val(ipr,0),AB=val(pr,1),BA=val(ipr,1),dd=0;
            upmin(A,AB);upmin(B,BA);upmin(AB,A+B);upmin(BA,B+A);
            if(AB>BA) swap(A,B),swap(AB,BA),dd=1;
            memset(del,0,sizeof(bool)*V[mpr.SE].size());
            for(int i=0,top=0;i<V[mpr.SE].size();i++)
            {
                if(d[V[mpr.SE][i]]==dd) stk[++top]=i;
                else if(top) del[stk[top]]=del[i]=1,top--,ans+=AB;
            }
            for(int i=0,top=0;i<V[mpr.SE].size();i++)
            {
                if(del[i]) continue;
                if(d[V[mpr.SE][i]]!=dd) stk[++top]=i;
                else if(top) del[stk[top]]=del[i]=1,top--,ans+=BA;
            }
            for(int i=0;i<V[mpr.SE].size();i++)
            {
                if(del[i]) continue;
                if(d[V[mpr.SE][i]]==dd) ans+=A;
                else ans+=B;
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
    
    • 1

    信息

    ID
    1294
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者