因为 b[i] 是 1 到 n 之间的,所以每个点都有且仅有一个出度,则必定存在环,且从任意点出发一直走,最终都能走到环。
本题在于,要构造出一种 a[i] 的拆分方式,并以此构造有向边,将 a−b 变为一条 a 指向 b 的有向边并跳到 b,这样就可以使得一条路径最终只剩下首尾两个值,达到中间值都抵消的目的。a 和 b 必须要是一样的性质,例如 a[i]=2a−2b,由 a 指向 b,找环,同样可以使 ∑a[i]=0。只是本题没有必要构造得这么麻烦。
#include<bits/stdc++.h> usingnamespace std; constint maxn = 1e6 + 10; int T; int n, a[maxn]; int vis[maxn]; vector<int>ans; intmain(){ scanf("%d", &T); while (T--) { scanf("%d", &n); ans.clear(); fill(vis, vis + n + 1, 0); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i] = i - a[i]; //a[i]变b[i] } int i; for (i = 1; !vis[i]; vis[i] = 1, i = a[i]);//找环入口 int st = i; while (1) { //输出环 ans.push_back(i); i = a[i]; if (i == st)break; } printf("%d\n", (int)ans.size()); for (int u : ans)printf("%d ", u); printf("\n"); } return0; }