AGC002 简要题解
Posted arg-53
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AGC002 简要题解相关的知识,希望对你有一定的参考价值。
A
分情况讨论一下。。。
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b;
scanf("%d %d", &a, &b);
if (a <= 0 && b >= 0) {
puts("Zero");
} else if (b < 0) {
puts(((b - a + 1) & 1) ? "Negative" : "Positive");
} else {
puts("Positive");
}
return 0;
}
B
转移球就把是否有红球的标记在盒子间传递一下,注意转移后盒子为空的情况。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<int> sz(n, 1);
vector<uint8_t> c(n);
c[0] = 1;
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
x--; y--;
c[y] |= c[x];
sz[x]--;
sz[y]++;
if (sz[x] == 0) {
c[x] = 0;
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
ans += c[i];
}
cout << ans << endl;
return 0;
}
C
错误的贪心:为了使剩下的最大,每次都删掉两边最小的那个。
反例:40 50 1 60,若删掉两个,删去 60 + 1 显然比删去 40 + 50 更优。。。
正确的贪心:注意到删到最后一步时还剩下两根绳子,若有解的话两根绳子的长度和一定不小于 (L),于是可以找这样的相邻两根绳子,剩下的从外到内删就好了。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, len;
cin >> n >> len;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int ii = 0, mx = 0;
for (int i = 0; i < n - 1; i++) {
if (a[i] + a[i + 1] > mx) {
mx = a[i] + a[i + 1];
ii = i;
}
}
if (mx < len) {
cout << "Impossible
";
return 0;
}
cout << "Possible
";
for (int i = 0; i < ii; i++) {
cout << i + 1 << ‘
‘;
}
for (int i = n - 2; i > ii; i--) {
cout << i + 1 << ‘
‘;
}
cout << ii + 1 << ‘
‘;
return 0;
}
D
考虑一个 naive 的询问过程:把边按照边权从小到大的顺序插入并查集,每插一条就检查一下两个询问点 (x, y) 能够到达的点个数是否大于等于 (z)。
这个过程可以对多个询问产生贡献,可以反复这样做的同时对所有询问进行二分。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(m), b(m);
for (int i = 0; i < m; i++) {
scanf("%d %d", &a[i], &b[i]);
a[i]--; b[i]--;
}
int tt;
scanf("%d", &tt);
vector<int> qa(tt), qb(tt), qc(tt);
for (int i = 0; i < tt; i++) {
scanf("%d %d %d", &qa[i], &qb[i], &qc[i]);
qa[i]--; qb[i]--;
}
vector<int> ql(tt), qr(tt);
for (int i = 0; i < tt; i++) {
ql[i] = -1;
qr[i] = m - 1;
}
vector<int> p(n), sz(n);
vector< vector<int> > id(m);
function<int(int)> root = [&](int x) {
return x == p[x] ? x : (p[x] = root(p[x]));
};
auto unite = [&](int x, int y) {
x = root(x);
y = root(y);
if (x == y) {
return;
}
p[x] = y;
sz[y] += sz[x];
assert(sz[y] <= n);
};
auto real_size = [&](int x, int y) {
x = root(x);
y = root(y);
if (x != y) {
return sz[x] + sz[y];
}
return sz[x];
};
for (int it = 0; it < 20; it++) {
for (int i = 0; i < m; i++) {
id[i].clear();
}
for (int i = 0; i < n; i++) {
p[i] = i;
sz[i] = 1;
}
for (int i = 0; i < tt; i++) {
if (qr[i] - ql[i] > 1) {
int mi = (ql[i] + qr[i]) >> 1;
id[mi].push_back(i);
}
}
for (int i = 0; i < m; i++) {
unite(a[i], b[i]);
for (int& qi : id[i]) {
if (real_size(qa[qi], qb[qi]) >= qc[qi]) {
qr[qi] = i;
} else {
ql[qi] = i;
}
}
}
}
for (int i = 0; i < tt; i++) {
printf("%d
", qr[i] + 1);
}
return 0;
}
E
做法太神了。。。但是没图不是很好理解,还是见题解吧。。。
http://agc002.contest.atcoder.jp/data/agc/002/editorial.pdf
抽象成这样一个图注意到斜对角的胜负态都一样,于是可以在图上一直往右上角走到死,然后看下剩下的两个方向能不能走到必胜态。。。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
a[i]--;
}
sort(a.begin(), a.end(), greater<int>());
int i = 0, j = 0;
while (i < n - 1 && a[i + 1] > j) {
i++;
j++;
}
int x = a[i] - j;
int y = 0;
while (i < n - 1 && j == a[i + 1]) {
i++;
y++;
}
if (x % 2 == 1 || y % 2 == 1) {
cout << "First
";
} else {
cout << "Second
";
}
return 0;
}
以上是关于AGC002 简要题解的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合