2021杭電多校賽第七場


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM