P9881 题解

· · 题解

模拟赛遇到这个题,写题解记录一下。

首先,因为每天一开始怪会先加 B ,因此我们对于 i \ge 2w_i 直接设置为 w_i+B

然后,分两种情况讨论。

对两种情况分别跑最短路即可,可能有一些细节吧。

#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define wang_shi return 0
using namespace std;
const int N=1e6+10;
typedef pair<int,int> PII;
int n,m,A,B,dis[N],vis[N],w[N],t[N];
vector<int> g[N];
void Solve1()
{
    for(int i=2;i<=n;++i)
    {
        if(A==B) t[i]=(w[1]>w[i]?1e18:0);
        else t[i]=(w[1]>w[i]?(w[1]-w[i]-1)/(B-A)+1:0);
        dis[i]=-1;
    }   
    queue<int> q; q.push(1);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int v:g[u])
        {
            if(dis[v]==-1&&dis[u]+1<=t[v])
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    cout<<dis[n]<<'\n'; 
}
void Solve2()
{
    for(int i=2;i<=n;++i)
    {
        t[i]=(w[1]>w[i]?1:(w[i]-w[1])/(A-B)+2);
        dis[i]=1e18;
    }
    priority_queue<PII,vector<PII>,greater<PII>> q;
    q.push({0,1}); int sum=0;
    while(!q.empty())
    {
        int u=q.top().se; q.pop();
        if(vis[u]) continue;
        if(sum<dis[u]){dis[u]=1e18;continue;}
        sum++;
        for(int v:g[u])
        {
            if(max(dis[u]+1,t[v])<dis[v])
            {
                dis[v]=max(dis[u]+1,t[v]);
                q.push({dis[v],v});
            }
        }
    }
    cout<<(dis[n]==1e18?-1:dis[n])<<'\n';
} 
void Solve()
{
    cin>>n>>m>>A>>B;
    for(int i=1;i<=m;++i) 
    {
        int u,v; cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for(int i=1;i<=n;++i)
    {
        cin>>w[i];
        w[i]+=(i==1?0:B);
    }
    if(A<=B) Solve1();
    else Solve2();
    for(int i=1;i<=n;++i)
    {
        w[i]=t[i]=dis[i]=vis[i]=0;
        g[i].clear();
    }   
}
signed main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    int t=1; cin>>t;
    while(t--) Solve();
    wang_shi;
}