1 条题解
-
0
自动搬运
来自洛谷,原作者为

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
- 上传者