The 2021 ICPC Asia Macau Regional Contest

发布时间 2023-10-06 14:31:54作者: PHarr

A. So I'll Max Out My Constructive Algorithm Skills

首先一行正一行反的把所有的行拼到一起,然后判断一下正着走时候合法不合法就反过来走就好。

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

void solve() {
    int n;
    cin >> n;
    vector<int> a;
    for (int i = 1; i <= n; i++) {
        vi b(n);
        for (auto &j: b) cin >> j;
        if (i & 1) reverse(b.begin(), b.end());
        for (auto j: b) a.push_back(j);
    }
    int x = 0, y = 0;
    for (int i = 1; i < a.size(); i++)
        x += (a[i] > a[i - 1]), y += (a[i] < a[i-1]);
    if( x > y )
        reverse( a.begin(), a.end() );
    for( auto i : a)
        cout << i << " \n"[i == a.back()];
    return ;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

C. Laser Trap

我们发现,要删除的部分必须是过原点的直线的同一侧。所以我们可以把所有的点按照极角序排序,然后双指针截出 180 度内的所有点即可。

这道题目对精度的要求比较高。所以记得使用acosl(-1)来表示\(\pi\)

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

using db = long double;

struct Point {
    db x, y;

    Point(db x = 0, db y = 0) : x(x), y(y) {};
};

const db pi = acosl(-1), eps = 1E-18;

bool lt(db a, db b) { return a - b < -eps; }

bool le(db a, db b) { return a - b < eps; }

db theta(Point p) { return atan2(p.y, p.x); }


void solve() {
    int n;
    cin >> n;
    vector<db> a(n + n);
    Point p;
    for (int i = 0; i < n; i++)
        cin >> p.x >> p.y, a[i] = theta(p) + pi, a[i + n] = a[i] + 2.0 * pi;

    sort(a.begin(), a.end(), [](db x, db y) {
        return lt(x, y);
    });
    int res = n;
    for (int l = 0, r = -1; l < n; l++) {
        db t = a[l] + pi;
        while (r + 1 < a.size() and le(a[r + 1], t)) r++;
        res = min(res, r - l );
    }
    cout << res << "\n";
    return;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

F. Sandpile on Clique

首先如果序列的和大于\(n(n-2)\),则一定无解。对于其他情况,暴力的模拟若干次,如果进行若干次后依旧无解,就可以认为无解。现在考虑每一次分割可以相当于所有数加一,被操作的数减 n。现在考虑这个若干次的阈值是什么?构造的极限情况也不会超过\(2n\)

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;
using pii = pair<int, int>;

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, cnt = 0;
    cin >> n;
    vector<int> a(n);
    priority_queue<pii> q;
    for (int i = 0; i < n; i++)
        cin >> a[i], q.emplace(a[i], i);
    if (accumulate(a.begin(), a.end(), 0ll) > n * (n - 2)) {
        cout << "Recurrent\n";
        return 0;
    }

    for (int i, x , tt = n * 2 ; tt > 0 and q.top().first + cnt >= n - 1; tt --) {
        i = q.top().second, q.pop();
        x = (a[i] + cnt) / (n - 1), a[i] -= x * n, cnt += x;
        q.emplace(a[i], i);
    }
    if( *max_element(a.begin(), a.end() ) + cnt >= n - 1 ){
        cout << "Recurrent\n";
        return 0;
    }
    for (int i = 0; i < n; i++)
        cout << a[i] + cnt << " \n"[i == n - 1];
    return 0;
}

K. Link-Cut Tree

因为边的缘故,所以前缀所有的边的和也没有后面的一条边的权值打,所以前缀形成的环就是最小环。所有用并查集辅助建图,一旦成环就停止加边,然后把环找出来即可。

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;
using pii = pair<int, int>;

struct dsu {
    vi fa;

    dsu(int n = 0) : fa(n + 1, -1) {};

    int getfa(int x) {
        if (fa[x] < 0) return x;
        return fa[x] = getfa(fa[x]);
    }

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

    void merge(int x, int y) {
        x = getfa(x), y = getfa(y);
        if (x == y) return;
        if (fa[x] > fa[y]) swap(x, y);
        fa[x] += fa[y], fa[y] = x;
        return;
    }
};

void solve() {
    int n, m, root = -1;
    cin >> n >> m;
    vector<pii> e(m);
    for (auto &[x, y]: e) cin >> x >> y;
    dsu d(n);
    vector g(n + 1, vector<pii>());
    for (int i = 0; const auto &[x, y]: e) {
        g[x].emplace_back(y, i), g[y].emplace_back(x, i);
        i++;
        if (d.same(x, y)) {
            root = x;
            break;
        }
        d.merge(x, y);
    }
    if (root == -1) {
        cout << "-1\n";
        return;
    }

    vi vis(m + 1), res;
    auto dfs = [g, &vis, & res](auto &&self, int x, int fa, int t) -> void {
        if (!res.empty()) return;
        if (t == 1) {
            for (auto [y, id]: g[x]) {
                if (y == fa) continue;
                if (vis[id] == 2) {
                    for (int i = 0; i < vis.size(); i++)
                        if (vis[i] == 2) res.push_back(i + 1);
                    return;
                }
                vis[id] = 2;
                self(self, y, x, 1);
                vis[id] = 1;
            }
        } else {
            for (auto [y, id]: g[x]) {
                if (y == fa) continue;
                if (vis[id] == 1) {
                    vis[id] = 2;
                    self(self, y, x, 1);
                    vis[id] = 1;
                } else {
                    vis[id] = 1;
                    self(self, y, x, 0);
                    vis[id] = 0;
                }
            }
        }

        return;
    };
    dfs(dfs, root, -1, 0);
    sort(res.begin(), res.end());
    for (auto i: res)
        cout << i << " \n"[i == res.back()];
    return ;
}


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}