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;
}