SMU Autumn 2024 Personal Round 2

SMU Autumn 2024 Personal Round 2

A. Not Adjacent Matrix

思路

可以按照奇数列就向上移动一个元素,溢出的元素补到最后一行,这样构造后检查一下是否有相邻元素即可(事实上只有 \(n=1\) 才会无解)。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    int n;
    cin >> n;

    vector a(n + 1, vector<int>(n + 1));
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) {
            a[i][j] = (i - 1) * n + j;
        }
    }

    for (int i = 1; i <= n; i ++) {
        if (i & 1) {
            auto t = a[1][i];
            for (int j = 2; j <= n; j ++) {
                a[j - 1][i] = a[j][i];
            }
            a[n][i] = t;
        }
    }

    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j < n; j ++) {
            if (a[i][j] == a[i][j + 1] + 1 || a[i][j] == a[i][j + 1] - 1) {
                cout << -1 << '\n';
                return ;
            }
        }
    }

    for (int i = 1 ; i <= n; i ++)
        for (int j = 1; j <= n; j ++)
            cout << a[i][j] << " \n"[j == n];

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

B. Alyona and Numbers

思路

要求 $(x+y) \equiv0\pmod{5} $ 的数量,其实只要看 \(x,y\) 的余数互补情况即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    int M[6] {};
    for (int i = 1; i <= m; i ++) {
        M[i % 5]++;
    }

    i64 ans = 0;
    for (int i = 1; i <= n; i ++) {
        ans += M[(5 - (i % 5)) % 5];
    }

    cout << ans << '\n';

    return 0;
}

C. Pleasant Pairs

思路

\(a_i\)从小到大排序,然后暴力枚举数对匹配即可,当 \(a_i \times a_j \ge 4\times 10^5\) 时退出即可。

复杂度 \(O(nlogn)\)

因为对于 \(a_i=1\),最多匹配 \(\frac {4\times 10 ^ 5}{1}\) 次,\(a_i = 2\),最多匹配 \(\frac {4\times 10 ^ 5}{2}\) 次,\(\dots\),对于 \(a_i=k\),最多匹配 \(\frac {4\times 10 ^ 5}{k}\) 次,即不会跑满 \(O(n^2)\),近似 \(O(nlogn)\)

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    int n;
    cin >> n;

    vector<array<i64, 2>> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        i64 x;
        cin >> x;
        a[i] = {x, i};
    }

    sort(a.begin() + 1, a.end());

    i64 ans = 0;
    for (int i = 1; i <= n; i ++) {
        auto [x, xi] = a[i];
        for (int j = 1; j < i; j ++) {
            auto [y, yi] = a[j];
            if (x * y > 2 * n) break;
            if (x * y == xi + yi) {
                ans ++;
            }
        }
    }

    cout << ans << '\n';

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

D. Hossam and Friends

思路

双指针维护题目所说的区间,对于一个新的 \(r\) ,判断能不能扩展到它,可以用 \(multiset\) 维护朋友关系,如果存在该关系,则可以扩展到它,否则就停止。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    int n, m;
    cin >> n >> m;

    vector g(n + 1, vector<int>());

    for (int i = 1; i <= m; i ++) {
        int u, v;
        cin >> u >> v;
        if (u > v) swap(u, v);
        g[u].push_back(v);
    }

    i64 ans = 0;
    multiset<int> s;
    for (int l = 1, r = 0; l <= n; l ++) {
        while (r + 1 <= n && !s.count(r + 1)) {
            r ++;
            for (auto v : g[r]) {
                s.insert(v);
            }
        }
        i64 len = r - l + 1;
        ans += len;
        for (auto v : g[l]) {
            s.erase(s.lower_bound(v));
        }
    }

    cout << ans << '\n';

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

E. Same Count One

思路

首先记所有 \(1\) 的数量为 \(num\),那么显然有当 \(n\mod num≠0\) 时无解。那么考虑有解的时候该怎么办。

显然对于每一个 \(a_i\) 序列中,最终 \(1\) 的数量为 $num $,记作 \(t\);并记 \(cnt_i\) 表示 \(a_i\) 序列中 \(1\) 的数量。

我们希望最终所有的 \(cnt_i\) 都等于 \(t\),并且希望操作步数最小,我们考虑一个显然的贪心:将 \(cnt_i>t\) 的序列中的 \(1\)\(cnt_j<t\) 缺失的 \(1\)

这样我们每一次的操作都会使 \(∑_{i=1}^n|cnt_i−t|\) 减少 \(2\),显然是最优的方案。

该题解转载:https://www.cnblogs.com/WaterSunHB/p/17962528/CF1774D

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    int n, m;
    cin >> n >> m;

    int cnt = 0;
    vector bnariy(n, vector<int>(m));
    vector<int> one(n);
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < m; j ++) {
            cin >> bnariy[i][j];
            one[i] += bnariy[i][j] == 1;
        }
        cnt += one[i];
    }

    if (cnt % n != 0) {
        cout << -1 << '\n';
        return ;
    }

    int avg = cnt / n;
    vector<array<int, 3>> ans;
    for (int j = 0; j < m; j ++) {
        vector<int> has, need;
        for (int i = 0; i < n; i ++) {
            if (one[i] > avg && bnariy[i][j]) {
                has.emplace_back(i);
            } else if (one[i] < avg && !bnariy[i][j]) {
                need.emplace_back(i);
            }
        }
        while (has.size() && need.size()) {
            auto x = has.back(), y = need.back();
            ans.push_back({x + 1, y + 1, j + 1});
            one[x] --, one[y] ++;
            has.pop_back(), need.pop_back();
        }
    }

    cout << ans.size() << '\n';
    for (auto [x, y, z] : ans) {
        cout << x << ' ' << y << ' ' << z << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

F. Shuffling Songs

思路

状压DP。

不过我用并查集减掉了很多不合法的状态,比如它不是个连通块。

然后就是把状态中的点拿出来,如果存在边则连上,最后对存在的点做状压DP即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

struct DSU {
    std::vector<int> f, siz;

    DSU() {}
    DSU(int n) {
        init(n);
    }

    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }

    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }
};

void solve() {

    int n;
    cin >> n;

    int cnt = 0;
    unordered_map<string, int> mp;
    vector<pair<int, int>> a;
    for (int i = 0; i < n; i ++) {
        string s1, s2;
        cin >> s1 >> s2;
        if (!mp.count(s1)) {
            mp[s1] = ++cnt;
        }
        if (!mp.count(s2)) {
            mp[s2] = ++cnt;
        }
        a.emplace_back(mp[s1], mp[s2]);
    }

    vector edge(n, vector<int>(n));
    for (int i = 0; i < n; i ++) {
        auto [s1, s2] = a[i];
        for (int j = 0; j < i; j ++) {
            auto [w1, w2] = a[j];
            if (s1 == w1 || s2 == w2) {
                edge[i][j] = edge[j][i] = 1;
            }
        }
    }

    int ans = n - 1;
    for (int i = 0; i < (1 << n); i ++) {

        if (__builtin_popcount(i) >= ans) {
            continue;
        }

        vector<int> now;
        for (int j = 0; j < n; j ++) {
            if (i >> j & 1) continue;
            now.emplace_back(j);
        }

        int m = n - __builtin_popcount(i);
        vector g(m, vector<int>());
        DSU d(m);
        for (int j = 0; j < m; j ++) {
            for (int p = 0; p < m; p ++) {
                if (edge[now[j]][now[p]]) {
                    g[j].emplace_back(p);
                    g[p].emplace_back(j);
                    d.merge(j, p);
                }
            }
        }

        if (d.size(0) != m) {
            continue;
        }

        const int inf = 100;
        vector dp(1 << m, vector<int>(m, inf));

        for (int j = 0; j < m; j ++) {
            dp[1 << j][j] = 1;
        }

        auto check = [&](int st)->bool{
            for (int k = 0; k < m; k ++) {
                if (st >> k & 1) {
                    for (auto p : g[k]) {
                        if (!(st >> p & 1)) {
                            auto nst = st | (1 << p);
                            dp[nst][p] = min(dp[nst][p], dp[st][k] + 1);
                            if (nst == (1 << m) - 1 && dp[nst][p] == m) {
                                ans = __builtin_popcount(i);
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        };

        for (int st = 0; st < (1 << m); st ++) {
            if (check(st)) {
                break;
            }
        }
    }

    cout << ans << '\n';

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}
posted @ 2024-11-03 20:51  Ke_scholar  阅读(1)  评论(0编辑  收藏  举报