2018-2019 ACM-ICPC, Asia Jiaozuo Regional Contest
A. Xu Xiake in Henan Province
if-else
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int a, b, c, d;
std::cin >> a >> b >> c >> d;
int s = (a > 0) + (b > 0) + (c > 0) + (d > 0);
if (s == 0) {
std::cout << "Typically Otaku\n";
} else if (s == 1) {
std::cout << "Eye-opener\n";
} else if (s == 2) {
std::cout << "Young Traveller\n";
} else if (s == 3) {
std::cout << "Excellent Traveller\n";
} else {
std::cout << "Contemporary Xu Xiake\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;
}
E. Resistors in Parallel
题意:选\(1\)和一些质数使得它们的乘积不超过\(n\)。设\(d_i\)为这些质数乘积的因子,则答案为\(\frac{1}{\frac{1}{d_1} + \frac{1}{d_2} + ... + \frac{1}{d_k}}\)。求最小的答案。
应该从小到大选质数,打表发现分母是每个选了的质数加1的乘积。
点击查看代码
import math
N = 10000
primes = []
minp = (N + 1) * [0]
for i in range(2, N + 1) :
if minp[i] == 0 :
minp[i] = i
primes.append(i)
for p in primes :
if p * i > N :
break
minp[p * i] = p
if minp[i] == p :
break;
t = int(input())
while t > 0:
t -= 1
n = int(input())
a = 1
b = 1
for p in primes :
if a * p > n :
break
a = a * p
b = b * (p + 1)
d = math.gcd(a, b)
a //= d
b //= d
print(str(a)+'/'+str(b))
F. Honeycomb
题意:用一个字符矩阵表示一个蜂巢,蜂巢有\(n \times m\)个房间,有些房间可以到其它房间。求起点到终点最少经过几个房间。
其实就是个\(bfs\)。但建边有点麻烦,需要找一下规律。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
const int N = 6e3 + 10;
char ss[N];
void solve() {
int n, m;
scanf("%d%d", &n, &m);
getchar();
std::vector<std::string> s(4 * n + 3);
for (int i = 0; i < 4 * n + 3; ++ i) {
gets(ss);
for (int j = 0; ss[j]; ++ j) {
s[i] += ss[j];
}
}
auto get = [&](int i, int j) -> int {
return i * m + j;
};
std::vector<std::vector<int>> adj(n * m);
auto addEdge = [&](int u, int v) -> void {
adj[u].push_back(v);
adj[v].push_back(u);
};
int S = -1, T = -1;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
if (j % 2 == 0) {
int x = i * 5 - i + 2, y = j / 2 * 9 + j / 2 * 3 + 4;
if (i > 0 && j + 1 < m) {
if (s[x - 1][y + 3] == ' ') {
addEdge(get(i, j), get(i - 1, j + 1));
}
}
if (j + 1 < m) {
if (s[x + 1][y + 3] == ' ') {
addEdge(get(i, j), get(i, j + 1));
}
}
if (i + 1 < n) {
if (s[x + 2][y] == ' ') {
addEdge(get(i, j), get(i + 1, j));
}
}
if (s[x][y] == 'S') {
S = get(i, j);
} else if (s[x][y] == 'T') {
T = get(i, j);
}
} else {
int x = i * 5 - i + 2 + 2, y = (j - 1) / 2 * 9 + (j - 1) / 2 * 3 + 4 + 6;
if (j + 1 < m) {
if (s[x - 1][y + 3] == ' ') {
addEdge(get(i, j), get(i, j + 1));
}
if (i + 1 < n && s[x + 1][y + 3] == ' ') {
addEdge(get(i, j), get(i + 1, j + 1));
}
}
if (i + 1 < n && s[x + 2][y] == ' ') {
addEdge(get(i, j), get(i + 1, j));
}
if (s[x][y] == 'S') {
S = get(i, j);
} else if (s[x][y] == 'T') {
T = get(i, j);
}
}
}
}
std::queue<int> q;
std::vector<int> d(n * m, -1);
d[S] = 1;
q.push(S);
while (q.size()) {
int u = q.front(); q.pop();
for (auto & v : adj[u]) {
if (d[v] == -1) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
printf("%d\n", d[T]);
}
int main() {
// std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
// std::cin >> t;
scanf("%d", &t);
while (t -- ) {
solve();
}
return 0;
}
I. Distance
题意:给你\(n\)个点,依次选点,新加入的点可以增加它和已有所有点之间距离的和的价值。求分别选\([1, n]\)的情况下可以得到的最大值。
思维。
依次从两边选点是最优的。记录一下前缀后缀的贡献模拟就行
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n + 1);
for (int i = 2; i <= n; ++ i) {
std::cin >> a[i];
a[i] += a[i - 1];
}
a.push_back(a.back());
std::vector<i64> ans(n + 1);
i64 pre = 0, suf = 0;
for (int i = 1, l = 1, r = n; i <= n; ++ i) {
if (i & 1) {
ans[i] = ans[i - 1] + pre + (l - 1) * (a[l] - a[l - 1]) + suf + (n - r) * (a[r + 1] - a[l]);
pre += (l - 1) * (a[l] - a[l - 1]);
++ l;
} else {
ans[i] = ans[i - 1] + pre + (l - 1) * (a[r] - a[l - 1]) + suf + (n - r) * (a[r + 1] - a[r]);
suf += (n - r) * (a[r + 1] - a[r]);
-- r;
}
}
for (int i = 1; i <= n; ++ i) {
std::cout << ans[i] << " \n"[i == 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;
}