【YbtOJ】困難遊走
阿新 • • 發佈:2020-11-23
題目
題目連結:https://www.ybtoj.com.cn/contest/67/problem/3
思路
下文設 \(\mathrm{stepsPerSecond}\) 為 \(t\),\(\mathrm{timeLimit}\) 為 \(m\)。
首先因為必須走 \(t\) 的倍數步,所以我們先求出走 \(t\) 步點兩兩之間的最遠距離。
設 \(f[l][i][j]\) 表示走 \(k\) 步後 \(i\) 與 \(j\) 之間的距離,那麼
這部分時間複雜度是 \(O(n^3t)\) 的。如果願意的話可以矩陣乘法優化到 \(O(n^3\log t)\)
然後後面很顯然只需要矩陣乘法 \(m\) 次即可。但是直接這樣做只可以求出嚴格走 \(m\) 秒後兩點之間的距離。
所以我們給終點與自己連一個自環即可。
時間複雜度 \(O(Tn^3(t+\log m))\)。
程式碼
#include <bits/stdc++.h> using namespace std; const int N=500010,M=1000010; int n,m,tot,ans0,ans1,head[2][N],maxd[2][N],deg[2][N],rk[N]; multiset<int> s; struct edge { int next,to; }e[M*2]; void add(int from,int to,int id) { e[++tot].to=to; e[tot].next=head[id][from]; head[id][from]=tot; } void topsort(int id) { tot=0; queue<int> q; for (int i=1;i<=n;i++) if (!deg[id][i]) q.push(i); while (q.size()) { int u=q.front(); q.pop(); rk[++tot]=u; for (int i=head[id][u];~i;i=e[i].next) { int v=e[i].to; deg[id][v]--; maxd[id][v]=max(maxd[id][v],maxd[id][u]+1); if (!deg[id][v]) q.push(v); } } } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for (int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y,0); deg[0][y]++; add(y,x,1); deg[1][x]++; } topsort(0); topsort(1); for (int i=1;i<=n;i++) s.insert(maxd[0][i]); ans1=2e9; for (int i=1;i<=n;i++) { int x=rk[i]; s.erase(s.find(maxd[0][x])); for (int j=head[0][x];~j;j=e[j].next) s.erase(s.find(maxd[0][x]+maxd[1][e[j].to]+1)); if (s.size() && *s.rbegin()<ans1) ans1=*s.rbegin(),ans0=x; s.insert(maxd[1][x]); for (int j=head[1][x];~j;j=e[j].next) s.insert(maxd[1][x]+maxd[0][e[j].to]+1); } printf("%d %d\n",ans0,ans1); return 0; }