2021“MINIEYE杯”中國大學生算法設計超級聯賽(7)
Link with Limit
根據極限的定義我們可以得出如下結論:
\(\bullet\) 題目所給\(f_n(x)\)必成環(包括自環)。
\(\bullet\) 對於屬於當前環的\(x\),它們的極限相同。
那么我們只需要讓每個\(i\)向\(f[i]\)連邊,求出每個環的平均值比較是否相同即可。
同時為了避免精度問題,我在判斷時分別存儲了分子分母。
循環
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int adj[MAXN], col[MAXN];
int main(int argc, char *argv[]) {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
memset(col, 0, sizeof(col));
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> adj[i];
}
bool f = true;
int idx = 0, up = 0, down = 0;
// up為分子
// down為分母
// solve用於更新up和down
auto solve = [&](int &x, int &y) -> void {
if (!up) {
up = x;
down = y;
}
if (up * y != down * x) {
f = false;
}
};
for (int i = 1; i <= n && f; ++i) {
if (col[i]) continue;
++idx;
int u = i;
while (!col[u]) {
col[u] = idx;
u = adj[u];
if (col[u] == idx) { // 下一個點已經訪問過代表出現環
int x = 0, y = 0;
// x為當前環的權值
// y為當前環的點數
for (int v = u; ; ) { // 遍歷環
x += adj[v], ++y;
v = adj[v];
if (v == u) {
solve(x, y);
break;
}
}
}
}
}
cout << (f ? "YES" : "NO") << '\n';
}
system("pause");
return 0;
}
tarjan
需要注意的是\(tarjan\)篩出的一些強聯通分量是不需要的,需要過濾掉。
如圖,\(tarjan\)篩出的\(4\)號點是不需要的。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int f[MAXN], w[MAXN]; // w表示每個scc的權值
stack<int> stk; bool ins[MAXN];
vector<int> e[MAXN], scc[MAXN];
int low[MAXN], dfn[MAXN], idx;
int sz[MAXN], belong[MAXN], sccn;
void dfs(int u) {
dfn[u] = low[u] = ++idx;
stk.push(u), ins[u] = true;
for (int v: e[u]) {
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (ins[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
++sccn;
int top;
do {
top = stk.top();
stk.pop();
++sz[sccn];
ins[top] = false;
belong[top] = sccn;
} while (u ^ top);
}
}
void tarjan(int n) {
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) {
dfs(i);
}
}
}
void init() {
idx = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
sccn = 0;
memset(sz, 0, sizeof(sz));
while (!stk.empty()) stk.pop();
memset(ins, false, sizeof(ins));
memset(belong, 0, sizeof(belong));
memset(w, 0, sizeof(w));
}
int main(int argc, char *argv[]) {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
init();
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
e[i].clear();
scc[i].clear();
}
for (int i = 1; i <= n; ++i) {
cin >> f[i];
e[i].push_back(f[i]);
}
tarjan(n);
for (int i = 1; i <= n; ++i) {
w[belong[i]] += f[i];
scc[belong[i]].push_back(i);
}
vector<pair<int, int>> V;
for (int i = 1; i <= sccn; ++i) {
// 如果是單點並且是自環
if (sz[i] == 1 && e[scc[i][0]][0] == scc[i][0]) {
V.push_back({w[i], 1});
}
else if (sz[i] > 1) {
V.push_back({w[i], sz[i]});
}
}
bool f = true;
for (int i = 1; i < V.size(); ++i) {
if (V[i].first * V[i - 1].second ^ V[i].second * V[i - 1].first) {
f = false;
}
}
cout << (f ? "YES" : "NO") << '\n';
}
system("pause");
return 0;
}