1 条题解

  • 0
    @ 2026-8-20 14:48:15

    牛逼题。

    初看这题,毫无思路,再看数据范围,这么小!那我们完全可以把每个巴士经过的路线全部存下来。

    于是我们模拟每个巴士的路线,然后对于每个点 (x,y)(x,y),记录所有经过它的巴士和该巴士到达这个点的最小时间。然后注意到巴士有一个周期,后面也要用到所以存下来。

    然后你跑一遍最短路,对于每个点 (x,y)(x,y),若你到达这个点的时间为 tt,你想要等经过这个点的某辆公交车,这辆公交车运行的周期为 cc,这辆公交车第一次到达这个点的时间为 ss,那么我们要求最小的非负整数 ww 使得:

    (t+w)modc=s\begin{aligned}(t+w)\bmod c=s \end{aligned}

    那么易得:

    w=(st)modc\begin{aligned}w=(s-t)\bmod c \end{aligned}

    由于要求非负,所以我们要给它取模后加上一个 cc,于是就变成了:

    $$\begin{aligned}w=((s-t)\bmod c+c)\bmod c \end{aligned}$$

    注意一定要先取模再加,至于为什么,可以看这篇帖子

    然后就做完了,你每个点松弛一下然后判断一下是否无解即可。

    ::::success[AC code]

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=2010,inf=1e9;
    int dis[N][N],point[N][N];//第一个到达这个点的是谁
    struct edge{
    	int x,y,w;
    };
    int H,W,n,stx,sty,enx,eny; 
    bool operator < (const edge &xx,const edge &yy){
    	return xx.w>yy.w;
    }
    priority_queue<edge> q;
    struct node{
    	int x,y,T,d,id;//走一次的周期,这辆公交第一次到达(x,y)这个位置的最小时间 
    }; 
    vector<node> g[N][N];//每个点的所有公交车
    void dj(){
    	for(int i=1;i<=H;i++){
    		for(int j=1;j<=W;j++){
    			dis[i][j]=inf;
    		}
    	}
    	dis[stx][sty]=0;
    	q.push({stx,sty,0});
    	while(q.size()){
    		int x=q.top().x,y=q.top().y;
    		if(dis[x][y]<q.top().w){
    			q.pop();continue;
    		}
    		if(x==enx&&y==eny)break;
    		q.pop();
    		for(auto tmp:g[x][y]){
    			int nx=tmp.x,ny=tmp.y,c=tmp.T;
    			int s=tmp.d,id=tmp.id;
    			int w=((s-dis[x][y])%c+c)%c;//在这个位置等到下一班车的时间
    			if(!w&&id!=point[x][y])w+=c;//防止两次都乘同一辆车 
    			if(dis[nx][ny]>dis[x][y]+w+1){//不能立马换乘所以要加一 
    				dis[nx][ny]=dis[x][y]+w+1;
    				point[nx][ny]=id;
    				q.push({nx,ny,dis[nx][ny]}); 
    			} 
    		}
    	}
    	if(dis[enx][eny]==inf)dis[enx][eny]=-1;
    	cout<<dis[enx][eny]<<"\n";
    } 
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>H>>W>>stx>>sty>>enx>>eny;
    	cin>>n;
    	for(int i=1,a,b,c,d,t;i<=n;i++){
    		cin>>a>>b>>c>>d>>t;
    		int C=(c-a+d-b)*2;//周长,走一圈的周期
    		t=(C-t)%C;
    		for(int j=a;j<=c-1;j++){//存公交车路线 
    			g[j][b].push_back({j+1,b,C,t,i});
    			t=(t+1)%C;
    		}
    		for(int j=b;j<=d-1;j++){
    			g[c][j].push_back({c,j+1,C,t,i});
    			t=(t+1)%C;
    		} 
    		for(int j=c;j>=a+1;j--){
    			g[j][d].push_back({j-1,d,C,t,i});
    			t=(t+1)%C;
    		}
    		for(int j=d;j>=b+1;j--){
    			g[a][j].push_back({a,j-1,C,t,i});
    			t=(t+1)%C;
    		}
    	}
    	dj();
    	return 0;
    }
    

    ::::

    • 1

    信息

    ID
    8988
    时间
    3000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者