AGC002 簡要題解
阿新 • • 發佈:2018-06-11
傳遞 auto begin ati bit 檢查 code cin int
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\n";
return 0;
}
cout << "Possible\n";
for (int i = 0; i < ii; i++) {
cout << i + 1 << ‘\n‘;
}
for (int i = n - 2; i > ii; i--) {
cout << i + 1 << ‘\n‘;
}
cout << ii + 1 << ‘\n‘;
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\n", 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\n";
} else {
cout << "Second\n";
}
return 0;
}
AGC002 簡要題解