【SSLOJ】最短路
阿新 • • 發佈:2020-08-10
題目
思路
容易發現從 \(i\) 到 \(j\) 的最優路徑一定是先往右再往左。因為如果某一時刻往左走後再往右走,那麼還不如在往左走的時刻直接往右走。
所以考慮如何求出 \(dis[i][j]\) 表示只往右走,\(i\) 到 \(j\) 的最短路。
那麼可以考慮列舉 \(j\),然後從 \(j-1\) 到 1 列舉 \(i\),容易發現走相同步數,走的越右顯然更優,所以可以利用單調性求出 \(dis[i][j]\)。
然後用類似 spfa 的想法,列舉 \(i\),將 \(dis[i][j]\) 從小到大排序,向前染色。每個點最多被染色一次。
時間複雜度 \(O(n^2)\)。
程式碼
#include <bits/stdc++.h> using namespace std; const int N=6010; int n,ans,a[N],b[N],dis[N][N],father[N]; bool used[N]; vector<int> pos[N]; int find(int x) { return x==father[x]?x:father[x]=find(father[x]); } int main() { scanf("%d",&n); for (int i=2;i<=n;i++) scanf("%d",&b[i]); for (int i=2;i<=n;i++) scanf("%d",&a[i]); for (register int i=1;i<=n;i++) { for (register int j=i-1,k=i;j>=1;j--) { while (a[k]>j) k--; dis[j][i]=dis[k][i]+1; } } b[1]=1; for (register int i=1;i<=n;i++) { for (register int j=0;j<=n;j++) { pos[j].clear(); used[j]=0; father[j]=j; } for (int j=i;j<=n;j++) pos[dis[i][j]].push_back(j); for (register int j=0;j<=n;j++) for (register int k=0;k<pos[j].size();k++) { int p=pos[j][k]; if (used[p]) continue; used[p]=1; for (int q=find(p);q>=b[p];q=find(q)) { if (dis[i][q]>dis[i][p]+1 || (dis[i][q]==0 && i!=q)) dis[i][q]=dis[i][p]+1; pos[dis[i][q]].push_back(q); father[q]=find(q-1); } } } for (register int i=1;i<=n;i++) for (register int j=1;j<=n;j++) ans^=(i+j)*dis[i][j]; printf("%d",ans); return 0; }