The 2021 ICPC Asia Macau Regional Contest
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;
}