原题链接:https://www.luogu.com.cn/problem/P5663 。
更好的使用方式:https://www.luogu.com.cn/article/0o6pvn64 。
警告:严禁抄袭 。
分析
此题是一道图论的题目,可以将每个工人看成一个点,将双向的零件传送带看作无向边。
只管的做法是按照题目的描述规则,使用递归直接模拟,这样可以通过前 8 8 8 个测试点,得到 40 40 40 分。对于满分做法,需要观察这个无向图本身的性质,容易发现 x x x 号点生产一个 L L L 阶段零件时,如果能找到一条从 x x x 号点到 1 1 1 号点提供原材料。
通过样例 2 2 2 的情况,我们发现 3 3 3 号点到 1 1 1 号点有两条简单的路径,3 → 2 → 1 3\to2\to1 3 → 2 → 1 与 3 → 4 → 5 → 1 3\to4\to5\to1 3 → 4 → 5 → 1 。那么,如果 3 3 3 号点想生产第一阶段的零件,因为两条简单路径的最短长度是 2 2 2 ,因此至少要生产第 2 2 2 阶段的零件才能到达 1 1 1 号点。此外,所有大于 2 2 2 的偶数阶段也都是需要 1 1 1 号点给材料的,因此会有 3 → 2 → 1 ⋯ → 2 → 1 3\to2\to1\cdots\to2\to1 3 → 2 → 1 ⋯ → 2 → 1 这样的方式使得 1 1 1 号点提供原材料,因为可以通过 3 → 4 → 5 → 1 ⋯ → 5 → 1 3\to4\to5\to1\cdots\to5\to1 3 → 4 → 5 → 1 ⋯ → 5 → 1 的方式到达一号点。
由此可得,只需预处理出 1 1 1 号点到其他所有点的最短奇数路径和最短偶数路径的长度。当 x x x 号点生产一个 L L L 阶段的零件时,如果 L L L 是奇数且 L L L 大于等于 x x x 号点到 1 1 1 号点的最短奇数路径长度,就需要 1 1 1 号点生产原材料。如果 L L L 是偶数且 L L L 大于等于 x x x 号点到 1 1 1 号点的最短偶数路径长度,就需要 1 1 1 号点生产原材料。
AC 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <bits/stdc++.h> using namespace std;int n, m, Q; vector<int > g[100005 ];int odd[100005 ], even[100005 ]; queue<int > q;int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cin >> n >> m >> Q; for (int i = 1 ;i <= m;i++){ int u, v; cin >> u >> v; g[u].push_back (v); g[v].push_back (u); } memset (odd, 0x3f , sizeof (odd)); memset (even, 0x3f , sizeof (even)); even[1 ] = 0 ; q.push (1 ); while (!q.empty ()){ int u = q.front (); q.pop (); for (int i = 0 ;i < g[u].size ();i++){ int v = g[u][i]; bool flag = false ; if (odd[u] + 1 < even[v]){ even[v] = odd[u] + 1 ; flag = true ; } if (even[u] + 1 < odd[v]){ odd[v] = even[u] + 1 ; flag = true ; } if (flag) q.push (v); } } for (int i = 1 ;i <= Q;i++){ int a, L; cin >> a >> L; if (L % 2 == 0 && even[a] <= L) cout << "Yes" << endl; else if (L % 2 == 1 && odd[a] <= L) cout << "Yes" << endl; else cout << "No" << endl; } return 0 ; }
AC 记录:https://www.luogu.com.cn/record/197005888 。