JOI2014 バス通学【思维】
题目翻译
题面
大学生君要坐公交车上学。他的家和学校都在市内,他住在号结点,大学在号结点。
市有辆公交车,每辆公交车每天只开一次,从特定的时刻在某个站点出发,在特定的时刻到达某个站点,不能在中途上下车,且时间跨度不会超过一天。
每天要换乘巴士去学校,他换乘的时间可以忽略不计,即:如果要乘坐在时刻从站点出发的公交车,那么他只需要在时刻之前(包含这个时刻)到达站点。他可以重复走过一个车站。
要去学校上天课,每天上课的时间各不相同,现在他想知道,他每天最晚什么时候从家里出发不会迟到。
输入
第一行包括两个整数
接下来行,每行个整数,表示第辆公交车在时刻从站点出发,在时刻到达。时刻是从午夜零点开始经过了多少毫秒(这个没啥用吧)。
下一行包括一个整数,表示上学的天数
接下来行,每行一个整数表示第天必须要在时刻之前到校。
输出
行,个整数,表示答案,如果不能按时到校,输出
数据范围
样例
输入1
5 6
1 2 10 25
1 2 12 30
2 5 26 50
1 5 5 20
1 4 30 40
4 5 50 70
4
10
30
60
100
输出1
-1
5
10
30
输出2
3 8
1 2 1 5
1 3 0 1
1 3 2 8
2 3 2 3
2 3 3 4
2 3 4 5
2 3 5 6
2 3 6 7
6
3
4
5
6
7
8
输出2
0
0
0
1
1
2
小言(基本上是我的碎碎念,可以skip
这是一道布置在某谷上的作业题。
发现某谷上没有翻译,百度没有搜到翻译,我就去把原文翻译过来了。
翻完之后同学告诉我啊呸,我错乱了,是上有翻译,心态大崩。
只能说练习了日文能力和熟练使用翻译软件的能力?
哼哼,的翻译就是逐字逐句译出来的而已,没有灵魂(说得好像我自己的翻译就很优秀一样
但是某谷采纳译文之后居然不给署名,气抖冷,原创保护什么时候才能站起来。
题目解析
法一:贪心乱搞
由于我太菜了,不能像其他大佬那样很快地想到递推什么的,于是上来先乱搞。
贪心地想,我们先走到达时间小的边不容易迟到。
而显然越大,条件越宽松,所以把询问从小到大处理。
由于我们要求的东西是的时间,这个不方便搜索,所以从出发。
设表示为了不迟到,从出发到达的最晚时间,那么答案就是
更新答案的时候,沿着边走,记录下到达这个点的最大时间是多少,和这个点公交车的到达时间比较,如果公交车到得比我要求的最大时间还要晚,那就不能走这条边了。
之前把询问从小到大排序,可以发现前面较小求出来的可以用来更新更大时的,你想,之前上学时间早的时候的出发时间肯定不会比上学时间晚的时间更晚,即正确性是有保障的,只是可能不会那么优秀,所以取就好了。
所以一条边只会经过一次,之前用这条边更新了的答案在里面,后面可以直接用,不用再走一遍这条边,复杂度是。
法二:dp递推
发现啥时候到校和坐的最后一辆公交车息息相关。
设表示坐第辆公交车最晚几点出发,表示到达第个点最晚几点出发
将所有公交车拆成出发和到达,按时间从小到大排序,相互更新:
出发:用更新,相当于统计答案:到校的最晚时间等价于坐上最后那辆公交车的最晚时间。如果这辆公交车的起点是,那么坐上这辆车的最晚时间就是,否则坐上这辆车的最晚时间取决于到达起点的允许最晚出发时间,也就是。
到达:用更新:,如果可以坐上车,那么在出发也可以到达
由于是按照时间从小到大排序,如果大于的对答案不会产生影响——这个时候还没有更新到那么大,要么比小,要么没有值(无解,因为不可能从起点飞到来吧)
询问和出发的处理方式是一样的,询问的答案就是对应的
有个小细节:排序时,如果时间一样,先到达,再出发,因为一样的时间,可以到达之后在马上接着出发。
►Code View Ver.1
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define N 100005
#define M 300005
#define DEL 100000
#define INF 0x3f3f3f3f
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
return f*x;
}
/*
实际上是L时刻从n出发 求到达1的最晚时刻(也就是在路上花费时间最小
把询问从小到大处理 显然L大的边答案会更大
而且一个更大的L的答案可以用小的L产生的答案更新 所以每条边只会走1次
d[i]表示从n出发 到达i的最大时刻
*/
int n,m;
int d[N],ans[N];
struct node{
int v,x,y;
};
vector<node>G[N];
struct P{
int a,b,x,y;
}p[M];
struct Node{
int id,L;
}query[N];
bool cmp(P l,P r)
{
return l.y>r.y;
//先搜到到站时间小的边 到站时间越靠前 越容易合法(不迟到
//而我不会删除vector第一个元素 只知道popback qwq
}
bool cmp2(Node l,Node r)
{
return l.L<r.L;
}
void dfs(int u,int t)
{//可以到达u的最晚时间为t
d[u]=max(d[u],t);
for(int i=G[u].size()-1;i>=0;i--)
{
int v=G[u][i].v;
if(t<G[u][i].y) return ;//最晚时间都比到达时间早 那肯定会迟到
dfs(v,G[u][i].x);
G[u].pop_back();
}
}
int main()
{
n=rd(),m=rd();
for(int i=1;i<=m;i++)
p[i].a=rd(),p[i].b=rd(),p[i].x=rd(),p[i].y=rd();
sort(p+1,p+m+1,cmp);
for(int i=1;i<=m;i++)
{
node t;
t.v=p[i].a,t.x=p[i].x,t.y=p[i].y;
G[p[i].b].push_back(t);
}
int Q=rd();
for(int i=1;i<=Q;i++)
query[i].L=rd(),query[i].id=i;
sort(query+1,query+Q+1,cmp2);
d[1]=-1;
for(int i=1;i<=Q;i++)
{
dfs(n,query[i].L);
ans[query[i].id]=d[1];
}
for(int i=1;i<=Q;i++)
printf("%d\n",ans[i]);
return 0;
}
►Code View Ver.2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define N 100005
#define M 300005
#define INF 0x3f3f3f3f
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
return f*x;
}
int n,m;
int f[M<<1]/*询问也在这*/,g[N];
struct node{
int x,t,id,typ;
};
vector<node>query;
bool cmp(node p,node q)
{
if(p.t==q.t)/*之前这里双等号写成了等号 调好久*/
return p.typ>q.typ;//到达在出发前面
return p.t<q.t;
}
int main()
{
n=rd(),m=rd();
for(int i=1;i<=m;i++)
{
int u=rd(),v=rd(),x=rd(),y=rd();
node tmp;tmp.x=u,tmp.t=x,tmp.id=i,tmp.typ=0;
query.push_back(tmp);
tmp.x=v,tmp.t=y,tmp.typ=1;
query.push_back(tmp);
}
int Q=rd();
for(int i=1;i<=Q;i++)
{
int L=rd();
node tmp;
tmp.x=n,tmp.t=L,tmp.id=m+i,tmp.typ=0;
query.push_back(tmp);
}
sort(query.begin(),query.end(),cmp);
memset(g,-1,sizeof(g));
for(int i=0;i<query.size();i++)
{
int x=query[i].x,id=query[i].id;
if(query[i].typ==0)
{//出发
if(x==1) f[id]=query[i].t;
else f[id]=g[x];
}
else//到达
g[x]=max(g[x],f[id]);
}
for(int i=1;i<=Q;i++)
printf("%d\n",f[m+i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现