VP 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest
A. Adrien and Austin
题意:\(n\)个石头,每次可以连续拿\(1\)到\(k\)个,拿过的不可以再拿。不可以拿的输。求赢家。
大量试样例后,觉得除了\(k=1\)的情况需要讨论奇偶,其它情况都是第一个人赢。注意\(n=0\)是第二个人赢。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, k;
std::cin >> n >> k;
if (n == 0 || (k == 1 && n % 2 == 0)) {
std::cout << "Austin\n";
} else {
std::cout << "Adrien\n";
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
D. Country Meow
题意:给你\(n\)个三维点,你要选一个点,使得它和最远的点的距离最小。
如果是二维,在固定了\(x\)的情况下,其实是个开口向下的二次函数,那么猜测三维在固定\(x, y\)的情况下也是单峰函数。套三个三分就行了。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<int> x(n), y(n), z(n);
for (int i = 0; i < n; ++ i) {
std::cin >> x[i] >> y[i] >> z[i];
}
auto get = [&](double x1, double y1, double z1, double x2, double y2, double z2) -> double {
double dx = x1 - x2, dy = y1 - y2, dz = z1 - z2;
return dx * dx + dy * dy + dz * dz;
};
auto check2 = [&](double X, double Y, double Z) -> double {
double res = 0;
for (int i = 0; i < n; ++ i) {
res = std::max(res, get(X, Y, Z, x[i], y[i], z[i]));
}
return res;
};
auto check1 = [&](double x, double y) -> double {
double l = -100000, r = 100000;
double ans = 1e18;
for (int i = 0; i < 100; ++ i) {
double mid1 = l + (r - l) / 3, mid2 = l + (r - l) * 2 / 3;
double ansl = check2(x, y, mid1), ansr = check2(x, y, mid2);
ans = std::min({ans, ansl, ansr});
if (ansl < ansr) {
r = mid2;
} else {
l = mid1;
}
}
return ans;
};
auto check = [&](double x) -> double {
double l = -100000, r = 100000;
double ans = 1e18;
for (int i = 0; i < 100; ++ i) {
double mid1 = l + (r - l) / 3, mid2 = l + (r - l) * 2 / 3;
double ansl = check1(x, mid1), ansr = check1(x, mid2);
ans = std::min({ans, ansl, ansr});
if (ansl < ansr) {
r = mid2;
} else {
l = mid1;
}
}
return ans;
};
double l = -100000, r = 100000;
double ans = 1e18;
for (int i = 0; i < 100; ++ i) {
double mid1 = l + (r - l) / 3, mid2 = l + (r - l) * 2 / 3;
double ansl = check(mid1), ansr = check(mid2);
ans = std::min({ans, ansl, ansr});
if (ansl < ansr) {
r = mid2;
} else {
l = mid1;
}
}
std::cout << std::fixed << std::setprecision(12);
std::cout << std::sqrt(ans) << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
G. Pyramid
题意:\(n\)层的三角形金字塔有多少等边三角形,包含斜着的。
不好说,只能打表模拟。得出\(C(n + 3, 4)\)。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
const int mod = 1e9 + 7;
i64 power(i64 a, i64 b) {
i64 res = 1;
for (;b;b >>= 1, a = a * a % mod) {
if (b & 1) {
res = res * a % mod;
}
}
return res;
}
i64 inv = power(24, mod - 2);
void solve() {
i64 n;
std::cin >> n;
i64 ans = (n + 3) * (n + 2) % mod * (n + 1) % mod * n % mod * inv % mod;
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
I. Magic Potion
题意:\(n\)个英雄\(m\)个怪物。每个英雄只能杀固定的一些怪物,且只能杀一个。但你可以选择\(k\)个不同的英雄让他们多杀一个。求最多杀多少怪物。
虽说是很简单的网络流,但签到题考网络流合理吗。
其实是个二分图匹配,但有些点可以多匹配一个,新建一个点从源点给它连容量为\(k\)的边,然后这个点向每个英雄连容量为\(1\)的边。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
const int N = 1000 + 10, M = (500 * 500 + 500 * 3 + 1) * 2 + 10, INF = 1e8;
int head[N], ver[M], cap[M], next[M], tot;
int d[N], cur[N];
int S, T;
void add(int x, int y, int z) {
ver[tot] = y; cap[tot] = z; next[tot] = head[x]; head[x] = tot ++ ;
ver[tot] = x; cap[tot] = 0; next[tot] = head[y]; head[y] = tot ++ ;
}
bool bfs() {
memset(d, -1, sizeof d);
std::queue<int> q;
d[S] = 0, cur[S] = head[S];
q.push(S);
while (q.size()) {
int u = q.front(); q.pop();
for (int i = head[u]; i != -1; i = next[i]) {
int v = ver[i];
if (d[v] == -1 && cap[i]) {
d[v] = d[u] + 1;
cur[v] = head[v];
if (v == T) {
return true;
}
q.push(v);
}
}
}
return false;
}
int find(int u, int limit) {
if (u == T) {
return limit;
}
int flow = 0;
for (int i = cur[u]; i != -1 && flow < limit; i = next[i]) {
int v = ver[i];
cur[u] = i;
if (d[v] == d[u] + 1 && cap[i]) {
int t = find(v, std::min(cap[i], limit - flow));
if (t == 0) {
d[v] = -1;
} else {
cap[i] -= t; cap[i ^ 1] += t;
flow += t;
}
}
}
return flow;
}
int dinic() {
int r = 0, flow;
while (bfs()) {
while (flow = find(S, INF)) {
r += flow;
}
}
return r;
}
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
S = n + m + 1, T = n + m + 2;
int V = n + m + 3;
memset(head, -1, sizeof head);
for (int i = 1; i <= n; ++ i) {
int t;
std::cin >> t;
while (t -- ) {
int j;
std::cin >> j;
add(i, j + n, 1);
}
}
add(S, V, k);
for (int i = 1; i <= n; ++ i) {
add(S, i, 1);
add(V, i, 1);
}
for (int i = 1; i <= m; ++ i) {
add(i + n, T, 1);
}
std::cout << dinic() << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
J. Prime Game
题意:给你一个数组,求所有子区间乘积的不同质因子的个数的和。
对于每个数枚举它的质因子,记录每个质因子上一次出现的位置为\(last\),那么这个质因子贡献为\((i - last) \times (n - i + 1)\)。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
std::vector<int> primes, minp;
void sieve(int n) {
primes.clear();
minp.assign(n + 1, 0);
for (int i = 2; i <= n; ++ i) {
if (minp[i] == 0) {
minp[i] = i;
primes.push_back(i);
}
for (auto & p : primes) {
if (p * i > n) {
break;
}
minp[p * i] = p;
if (minp[i] == p) {
break;
}
}
}
}
void solve() {
sieve(1e6);
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::map<int, int> last;
i64 ans = 0;
for (int i = 1; i <= n; ++ i) {
while (a[i] > 1) {
int t = minp[a[i]];
ans += (i64)(i - last[t]) * (n - i + 1);
while (a[i] % t == 0) {
a[i] /= t;
}
last[t] = i;
}
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
K. Kangaroo Puzzle
题意:一个矩阵,有些地方不能走,其它地方都有一个袋鼠,你每次下达上下左右的命令,所有袋鼠如果能走就会往这个方向走,你要让所有袋鼠在同一个位置。
找一个空地,然后让其它所有位置都找一条路径到这个位置。感觉没问题,结果\(wa\)了,然后把答案复制一遍到后面输出就过了。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
int sx = 0, sy = 0;
for (int i = 0; i < n; ++ i) {
bool flag = false;
for (int j = 0; j < m; ++ j) {
if (s[i][j] == '1') {
sx = i, sy = j;
flag = true;
break;
}
}
if (flag) {
break;
}
}
const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
std::vector d(n, std::vector<int>(m, -1));
std::vector pre(n, std::vector<int>(m, -1));
std::queue<std::pair<int, int>> q;
d[sx][sy] = 0;
q.emplace(sx, sy);
while (q.size()) {
auto [x, y] = q.front(); q.pop();
for (int i = 0; i < 4; ++ i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= m || d[nx][ny] != -1 || s[nx][ny] == '0') {
continue;
}
d[nx][ny] = d[x][y] + 1;
pre[nx][ny] = i ^ 1;
q.emplace(nx, ny);
}
}
std::string op = "UDLR";
std::string ans;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
if (s[i][j] == '0') {
continue;
}
int x = i, y = j;
while (pre[x][y] != -1) {
int t = pre[x][y];
ans += op[t];
x += dx[t], y += dy[t];
}
}
}
ans += ans;
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}