CF154C題解

Jefferyzzzz發表於2024-10-04

傳送門:https://codeforces.com/problemset/problem/154/C

求出無向圖中,滿足所有出邊都相連或出邊直接連線點對的點對數。很顯然可以暴力列舉點對一對對去check,時間複雜度\(O(n^2+m)\)

#include <bits/stdc++.h>

using namespace std;

inline int read() {
    char c;
    bool flag = false;
    while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
    int res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

const int N = 2e5 + 1;

int head[N], cnt, ans;
struct Edge {
    int v, next;
} e[N];

void add(int u, int v) {
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}

map<pair<int, int>, int> mp;

bool check(int x, int y) {
    for (int i = head[x]; ~i; i = e[i].next) {
        int to = e[i].v;
        if (to != y && !mp[make_pair(to, y)] && !mp[make_pair(y, to)]) return false;
    }
    for (int i = head[y]; ~i; i = e[i].next) {
        int to = e[i].v;
        if (to != x && !mp[make_pair(to, x)] && !mp[make_pair(x, to)]) return false;
    }
    return true;
}

int main() {
    memset(head, -1, sizeof head);
    int n = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        int u = read(), v = read();
        add(u, v);
        add(v, u);
        mp[make_pair(u, v)] = 1;
    }
    for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) if (check(i, j)) ++ans;
    printf("%d", ans);
    return 0;
}

考慮最佳化,列舉點對肯定不可行,如何快速判定兩點出邊抵達的點相同?我們不妨把點集看作一個數,這樣就能透過排序快速計算點集相同的點對,這裡可以同行集合雜湊來實現,分有邊直連的點對和無邊直連的點對兩種情況計數即可。時間複雜度\(O(nlog_{2}n)\),瓶頸在於排序。

#include <bits/stdc++.h>

typedef unsigned long long ull;
using namespace std;

inline int read() {
    char c;
    bool flag = false;
    while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
    int res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

const int N = 1e6 + 1;

ull p[N], hs[N];

int u[N], v[N];

int main() {
    int n = read(), m = read();
    p[0] = 1;
    for (int i = 1; i <= n; ++i) p[i] = p[i - 1] * 13;
    for (int i = 1; i <= m; ++i) {
        u[i] = read(), v[i] = read();
        hs[u[i]] += p[v[i]];
        hs[v[i]] += p[u[i]];
    }
    long long ans = 0;
    for (int i = 1; i <= m; ++i) if (hs[u[i]] + p[u[i]] == hs[v[i]] + p[v[i]]) ++ans;
    sort(hs + 1, hs + n + 1);
    int cnt = 1;
    for (int i = 2; i <= n; ++i) {
        if (hs[i] == hs[i - 1]) ++cnt;
        else {
            ans += 1ll * cnt * (cnt - 1) / 2;
            cnt = 1;
        }
    }
    ans += 1ll * cnt * (cnt - 1) / 2;
    printf("%lld", ans);
    return 0;
}