P9881 题解
模拟赛遇到这个题,写题解记录一下。
首先,因为每天一开始怪会先加
然后,分两种情况讨论。
-
A \leq B 令
t_i 为到达i 最晚时间。对于
w_1 \leq w_i ,显然永远也到达不了i ,t_i 直接设为0 。对于
w_1 > w_i ,有式子w_1+A(i-1) > w_i+B(i-1) ,移项得i < \frac{w_1-w_i}{B-A} ,因此t_i = \frac{w_1-w_i-1}{B-A} ,对于A=B 特殊判一下。 -
A > B 令
t_i 为到达i 最早时间。对于
w_1>w_i ,t_i=1 。对于
w_1 \leq w_i ,同样用上面的式子可以推出t_i = \frac{w_i-w_1}{B-A}+2 。
对两种情况分别跑最短路即可,可能有一些细节吧。
#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;
}