Adrien and Austin
特判 n = 0 n=0 n=0 或者 k = 1 k=1 k=1 的情况,当 k > 1 k>1 k>1 的时候,先手取中间,然后后手不管取什么先手取相对的,所以先手必胜。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
if (m == 1) {
puts(n & 1 ? "Adrien" : "Austin");
} else {
puts(n ? "Adrien" : "Austin");
}
return 0;
}
Tournament
凸优化+决策单调性DP。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
vector<long long> sum(n + 1);
vector<long long> f(n + 1);
vector<int> g(n + 1);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &sum[i]);
sum[i] += sum[i - 1];
}
vector<pair<int, int>> q(n);
auto solve = [&](long long cost) {
int ll = 0, rr = 0;
auto get = [&](int l, int r) {
return f[l] + cost + sum[l] + sum[r] - sum[l + r >> 1] - sum[l + r + 1 >> 1];
};
for (int i = 0; i < n; ++i) {
while (ll < rr && get(i, q[rr - 1].second) < get(q[rr - 1].first, q[rr - 1].second)) {
--rr;
}
if (ll == rr) {
q[rr++] = make_pair(i, i + 1);
} else {
int l = q[rr - 1].second, r = n + 1;
while (l < r) {
int mid = l + r >> 1;
if (get(i, mid) < get(q[rr - 1].first, mid)) {
r = mid;
} else {
l = mid + 1;
}
}
if (r <= n) {
q[rr++] = make_pair(i, r);
}
}
while (ll + 1 < rr && q[ll + 1].second <= i + 1) {
++ll;
}
f[i + 1] = get(q[ll].first, i + 1);
g[i + 1] = g[q[ll].first] + 1;
}
};
long long l = 0, r = sum[n];
while (l < r) {
long long mid = l + r >> 1;
solve(mid);
if (g[n] <= m) {
r = mid;
} else {
l = mid + 1;
}
}
solve(r);
printf("%lld\n", f[n] - r * m);
return 0;
}
Cherry and Chocolate
考虑第一个人选了一个点之后,第二个人一定会选择某个子树的重心,然后第一个人删去最大的那个子树。这时候我们求出了一个最优解,假设第一个人选的点不在第二个人当前这个解所在子树内,那么第二个人保持同样的决策答案不会对第一个人更优。每次选重心之后朝一个子树递归即可。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; ++i) {
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
adj[x].push_back(y);
adj[y].push_back(x);
}
int answer = 0;
vector<int> size(n), parent(n);
vector<bool> visit(n);
auto find_centroid = [&](int x, bool ban) {
vector<int> order(1, x);
for (int i = 0; i < order.size(); ++i) {
int x = order[i];
for (auto y : adj[x]) {
if ((!visit[y] || !ban) && y != parent[x]) {
order.push_back(y);
parent[y] = x;
}
}
}
int root = -1, value = n;
for (int i = order.size() - 1; ~i; --i) {
int x = order[i], subtree = 0;
size[x] = 1;
for (auto y : adj[x]) {
if ((!visit[y] || !ban) && y != parent[x]) {
size[x] += size[y];
subtree = max(subtree, size[y]);
}
}
subtree = max(subtree, (int)order.size() - size[x]);
if (subtree < value) {
root = x;
value = subtree;
}
}
return make_pair(root, value + n - (int)order.size());
};
auto get = [&](int x) {
pair<int, int> result = make_pair(n, -1);
for (auto y : adj[x]) {
parent[y] = x;
result = min(result, make_pair(find_centroid(y, false).second, y));
}
return result;
};
int x = 0;
while (!visit[x]) {
parent[x] = -1;
x = find_centroid(x, true).first;
visit[x] = true;
pair<int, int> result = get(x);
answer = max(answer, result.first);
x = result.second;
}
printf("%d\n", answer);
return 0;
}
Country Meow
三分套三分套三分。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<vector<int>> a(3, vector<int> (n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 3; ++j) {
scanf("%d", &a[j][i]);
}
}
vector<double> p(3);
function<double(int)> ternary_search = [&](int x) {
if (x == 3) {
double answer = 0;
for (int i = 0; i < n; ++i) {
double result = 0;
for (int j = 0; j < 3; ++j) {
result += (p[j] - a[j][i]) * (p[j] - a[j][i]);
}
answer = max(answer, result);
}
return answer;
} else {
double l = *min_element(a[x].begin(), a[x].end());
double r = *max_element(a[x].begin(), a[x].end()