P10053 题解
简要题意:一天有
首先答案必然有一个上界
我们考虑一个人可能走的两种情况:
- 在一天之内完成了整个路程。
- 用至少两天完成了整个路程。
第二种情况
对于第二种情况,我们可以将其分解成三段:第一天,中间的若干天(可能没有),最后一天。我们逐个来考虑。
第一天
考虑路径
这个过程类似最短路可以使用 Dijkstra 实现,以每一个点为起点跑一遍,时间复杂度
最后一天
考虑路径
这个也可以使用 Dijkstra 实现,以每一个点为起点跑一遍,时间复杂度
中间的若干天
每一天都可以看作是一条和“最后一天”相同的路径,利用最后一天对应的数组来生成一张图:如果可以从
然后在这张图上跑 Floyd 即可,时间复杂度
考虑如何计算对于答案的贡献,一个很暴力的想法是枚举第一天的终点
我们考虑到
第一种情况
我们考虑一条从
我们考虑枚举这条边
对于某一对
对于每一对
考虑时间复杂度:对于枚举每一条边跑一次 Dijkstra,时间复杂度为
总体时间复杂度为
#include "escape_route.h"
#include <bits/stdc++.h>
using namespace std;
template<typename T>bool get_max(T &a,T b){if(a<b) return a=b,true;return false;}
template<typename T>bool get_min(T &a,T b){if(a>b) return a=b,true;return false;}
vector<long long> ans;
vector<pair<int,int> >ed[100];
vector<pair<long long,long long> >mind[100][100],tmp;
priority_queue<pair<long long,int>,vector<pair<long long,int> >,greater<pair<long long,int> > > G;
priority_queue<pair<long long,int> >G_;
long long dis[100][100],tr[100][100];
long long sid[100][100];
long long dis1[100],dis2[100];
int f[100][100];
bool vis[100];
vector<long long> calculate_necessary_time(
int N, int M, long long S, int Q, vector<int> A, vector<int> B,
vector<long long> L, vector<long long> C, vector<int> U,
vector<int> V, vector<long long> T)
{
ans.resize(Q);
for(int i=0;i<M;i++)
ed[A[i]].push_back(make_pair(B[i],i)),
ed[B[i]].push_back(make_pair(A[i],i));
//solve go in days
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++) dis[i][j]=S*N,vis[j]=false;
dis[i][i]=0;G.push(make_pair(0ll,i));
while(!G.empty())
{
int v=G.top().second;G.pop();
if(vis[v]) continue;
vis[v]=true;
for(pair<int,int> g:ed[v])
if(dis[i][v]+L[g.second]<=C[g.second]&&dis[i][g.first]>dis[i][v]+L[g.second])
G.push(make_pair(dis[i][g.first]=dis[i][v]+L[g.second],g.first));
}
for(int j=0;j<N;j++)
f[i][j]=(dis[i][j]<S?1:N+1);
}
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++) sid[i][j]=-1,vis[j]=false;
sid[i][i]=S;G_.push(make_pair(S,i));
while(!G_.empty())
{
int v=G_.top().second;G_.pop();
if(vis[v]) continue;
vis[v]=true;
for(pair<int,int> g:ed[v])
if(get_max(sid[i][g.first],min(sid[i][v],C[g.second])-L[g.second]))
G_.push(make_pair(sid[i][g.first],g.first));
}
}
for(int i=0;i<N;i++)
f[i][i]=0;
for(int k=0;k<N;k++)
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
tr[i][j]=f[i][j]*S;
for(int k=0;k<N;k++)
tr[i][j]=min(tr[i][j],f[i][k]*S+dis[k][j]);
}
//solve go in one day
for(int i=0;i<M;i++)
{
//A[i]->B[i]
memset(dis1,0xcf,sizeof(dis1));
memset(dis2,0x3f,sizeof(dis2));
dis1[A[i]]=C[i]-L[i],dis2[B[i]]=C[i];
memset(vis,0,sizeof(vis));
for(int j=0,mx;j<N;j++)
{
mx=-1;
for(int k=0;k<N;k++)
if(!vis[k]&&(mx==-1||dis1[mx]<dis1[k]))
mx=k;
vis[mx]=true;
for(pair<int,int> g:ed[mx])
if(dis1[mx]<=C[g.second]&&dis1[g.first]<dis1[mx]-L[g.second])
dis1[g.first]=dis1[mx]-L[g.second];
}
memset(vis,0,sizeof(vis));
for(int j=0,mn;j<N;j++)
{
mn=-1;
for(int k=0;k<N;k++)
if(!vis[k]&&(mn==-1||dis2[mn]>dis2[k]))
mn=k;
vis[mn]=true;
for(pair<int,int> g:ed[mn])
if(dis2[mn]<=C[g.second]-L[g.second]&&dis2[g.first]>dis2[mn]+L[g.second])
dis2[g.first]=dis2[mn]+L[g.second];
}
for(int x=0;x<N;x++)
for(int y=0;y<N;y++)
if(dis1[x]>=0&&dis2[y]<=S)
mind[x][y].push_back(make_pair(dis1[x],dis2[y]-dis1[x]));
//B[i]->A[i]
memset(dis1,0xcf,sizeof(dis1));
memset(dis2,0x3f,sizeof(dis2));
dis1[B[i]]=C[i]-L[i],dis2[A[i]]=C[i];
memset(vis,0,sizeof(vis));
for(int j=0,mx;j<N;j++)
{
mx=-1;
for(int k=0;k<N;k++)
if(!vis[k]&&(mx==-1||dis1[mx]<dis1[k]))
mx=k;
vis[mx]=true;
for(pair<int,int> g:ed[mx])
if(dis1[mx]<=C[g.second]&&dis1[g.first]<dis1[mx]-L[g.second])
dis1[g.first]=dis1[mx]-L[g.second];
}
memset(vis,0,sizeof(vis));
for(int j=0,mn;j<N;j++)
{
mn=-1;
for(int k=0;k<N;k++)
if(!vis[k]&&(mn==-1||dis2[mn]>dis2[k]))
mn=k;
vis[mn]=true;
for(pair<int,int> g:ed[mn])
if(dis2[mn]<=C[g.second]-L[g.second]&&dis2[g.first]>dis2[mn]+L[g.second])
dis2[g.first]=dis2[mn]+L[g.second];
}
for(int x=0;x<N;x++)
for(int y=0;y<N;y++)
if(dis1[x]>=0&&dis2[y]<=S)
mind[x][y].push_back(make_pair(dis1[x],dis2[y]-dis1[x]));
}
for(int x=0;x<N;x++)
for(int y=0;y<N;y++)
if(mind[x][y].size())
{
sort(mind[x][y].begin(),mind[x][y].end(),[&](pair<long long,long long> A,pair<long long,long long> B)
{if(A.first!=B.first) return A.first<B.first;else return A.second>B.second;});
vector<pair<long long,long long> >().swap(tmp);
for(pair<long long,long long> &g:mind[x][y])
{
while(!tmp.empty()&&tmp.rbegin()->second>g.second) tmp.pop_back();
tmp.push_back(g);
}
swap(tmp,mind[x][y]);
}
vector<pair<long long,long long> >::iterator it;
for(int i=0;i<Q;i++)
{
if((it=lower_bound(mind[U[i]][V[i]].begin(),mind[U[i]][V[i]].end(),make_pair(T[i],0ll)))!=mind[U[i]][V[i]].end())
ans[i]=it->second;
else ans[i]=(N+1)*S;
if(T[i]<=sid[V[i]][U[i]])
get_min(ans[i],S-sid[V[i]][U[i]]);
for(int j=0;j<N;j++)
if(T[i]<=sid[j][U[i]])
get_min(ans[i],S-T[i]+tr[j][V[i]]);
}
return ans;
}
注:需要写标准输入输出,而不是 JOISC 的交互。