比赛链接:
https://codeforces.com/contest/1679
D. Toss a Coin to Your Graph...
题目大意:
一个有向图,每个点有一个权值,从一个点出发,向它可以到达的点进发,总共走 \(k\) 步,\(x\) 为这 \(k\) 步之后经过的所有点的权值的最大值,问 \(x\) 最大能是多少。
思路:
因为最大值是单调的,所以二分答案,记二分的值为 \(x\)。
再去图中找所有值小于 \(x\) 的边,构建一个图,这个图为拓扑图,如果图中中有一个环或者长度大于 \(k\) 的链,那么 \(x\) 一定可以出现。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define LL long long
LL n, m, k;
vector <int> a(N), g[N];
bool check(LL x){
vector <int> in(n + 1);
int cnt = 0;
for (int u = 1; u <= n; u ++ ){
if (a[u] > x) continue;
cnt ++ ;
for (auto v : g[u]){
if (a[v] > x) continue;
in[v] ++ ;
}
}
vector <int> q;
for (int v = 1; v <= n; v ++ )
if (a[v] <= x && !in[v])
q.push_back(v);
vector <int> d(n + 1);
for (int i = 0; i < (int)q.size(); i ++ ){
int u = q[i];
d[u] = max(d[u], 1);
for (auto v : g[u]){
if (a[v] > x) continue;
d[v] = max(d[v], d[u] + 1);
if (!--in[v]) q.push_back(v);
}
}
if (*max_element(d.begin(), d.end()) >= k || cnt > (int)q.size()) return true;
return false;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++ )
cin >> a[i];
for (int i = 0; i < m; i ++ ){
int u, v;
cin >> u >> v;
g[u].push_back(v);
}
LL l = 0, r = 1e9 + 1;
while (l < r){
LL mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << (r == (1e9 + 1) ? -1 : r) << "\n";
return 0;
}