比赛链接:
https://codeforces.com/contest/1725
A. Accumulation of Dominoes
题意:
\(n * m\) 的矩阵,从左上角开始,将 1 到 \(n * m\) 的数,放到矩阵中,先放第一行,从左到右,然后第二行,以此类推。问相邻且数字差为 1 的格子有多少个。
思路:
答案就是 \((m - 1) * n\),特判一下只有一列的情况即可。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long int main(){ ios::sync_with_stdio(false);cin.tie(0); LL n, m; cin >> n >> m; if (m == 1) cout << n - 1 << "\n"; else cout << (m - 1) * n << "\n"; return 0; }
B. Basketball Together
题意:
\(n\) 个人,每个能有一个能力值,将他们分组后,每组中所有人的能力值会变成组中最大能力者的能力值,问怎样分组能让小组能力值之和严格大于 \(D\)。
思路:
将能力值排序,然后从大到小遍历,判断需要多少个人才能让这个小组能力值严格大于 \(D\)。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long int main(){ ios::sync_with_stdio(false);cin.tie(0); LL n, d; cin >> n >> d; vector <int> a(n); for (int i = 0; i < n; i ++ ) cin >> a[i]; sort(a.begin(), a.end()); int ans = 0; for (int i = -1, j = n - 1; i < j; j -- ){ int k = d / a[j] + 1; if (i + k - 1 < j){ ans ++ ; } i += k - 1; } cout << ans << "\n"; return 0; }
G. Garage
题意:
如图,问下面那个正方形的面积第 \(n\) 小是多少。
思路:
打个暴力,枚举 \(a\) 和 \(b\) 找下面正方形的面积规律。
可以正方形的面积从小到大为
发现排除第一个,每三个都是两个奇数 + 一个 4 的倍数。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long int main(){ ios::sync_with_stdio(false);cin.tie(0); LL n; cin >> n; if (n == 1) cout << "3\n"; else{ LL k = (n - 1 + 2) / 3; if (n % 3 == 0){ cout << (k + 1) * 4 - 1 << "\n"; } else if (n % 3 == 1){ cout << (k + 1) * 4 << "\n"; } else{ cout << (k + 1) * 4 - 3 << "\n"; } } return 0; }
H. Hot Black Hot White
题意:
\(n\) 个数,将它们涂上黑和白两种颜色,要求涂上黑色的数的数量和涂上白色的数的数量相同。
定义 \(concat(a, b) = a * 10^{\lvert b \rvert}\),例如 \(concat(10, 24) = 10 * 10^2 + 24 = 1024\)。
现在要确定一个 \(Z\) 及一种涂色方法,使得对于任意不同颜色的两个数,不存在 \(concat(a, b) * concat(b, a) + a * b \equiv Z\) mod 3。
思路:
因为 \(10 \equiv 1\) mod 3,所以 \(concat(a, b)\) mod 3 = \((a^{10^k} + b)\) mod 3 = \((a + b)\) mod 3。
那么 \(concat(a, b) * concat(b, a) + a * b\) mod 3 = \((a + b) * (b + a) + a * b\) mod 3 = \(a^2 + b^2\) mod 3。
对于原序列,只需要记录平方 % 3 就行。
所有数字 \(mod 3\) 之后只会是 0,1,2。
0^2 % 3 = 0
1^2 % 3 = 1
2^2 % 3 = 1
平方后 % 3 只有两种情况。
记录序列中 0 和 1 的个数,当 0 的数量小于 1 的时候,将序列长度一半的 1 涂成同一个颜色,任意两个不同颜色的数的组合只可能为 1 或 2 了,让 \(Z\) 等于 0。
否则让 \(Z\) 等于 2,因为凑不出 2 来。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long int main(){ ios::sync_with_stdio(false);cin.tie(0); int n; cin >> n; vector <LL> a(n); int cnt0 = 0; for (int i = 0; i < n; i ++ ){ cin >> a[i]; a[i] = (a[i] * a[i]) % 3; if (a[i] == 0) cnt0 ++ ; } if (cnt0 <= n / 2){ cout << "0\n"; for (int i = 0, j = 0; i < n; i ++ ){ if (a[i] == 1 && j < n / 2){ cout << 0; j ++ ; } else cout << 1; } cout << "\n"; } else{ cout << "2\n"; for (int i = 0, j = 0; i < n; i ++ ){ if (a[i] == 0 && j < n / 2){ cout << 0; j ++ ; } else cout << 1; } cout << "\n"; } return 0; }
M. Moving Both Hands
题意:
\(n\) 个节点,\(m\) 条边的有向带权图,有两个点,一个在 1,两个点可以沿着有向边移动,对于另一个点在 2 到 \(n\) 的所有情况,问最短路径分别是多少。
思路:
对于另一个节点的移动,其实可以看成 1 在反图上的移动。
先在正图上跑一遍 \(dijkstra\),然后将能到达的点压入队列,再在反图上跑一遍即可。
代码:
#include <bits/stdc++.h> using namespace std; #define LL long long int main(){ ios::sync_with_stdio(false);cin.tie(0); int n, m; cin >> n >> m; vector < vector < array<LL, 2> > > g(n + 1), G(n + 1); for (int i = 1; i <= m; i ++ ){ int u, v, w; cin >> u >> v >> w; g[u].push_back({w, v}); G[v].push_back({w, u}); } auto dijkstra = [&](int s){ vector <LL> dis(n + 1, 1e18); vector <bool> vis(n + 1, false); dis[s] = 0; priority_queue < array<LL, 2>, vector < array<LL, 2> >, greater < array<LL, 2> > > q; q.push({0, s}); while(q.size()){ auto t = q.top(); q.pop(); int u = t[1]; if (vis[u]) continue; vis[u] = true; for (auto [w, v] : g[u]){ if (dis[v] > dis[u] + w){ dis[v] = dis[u] + w; q.push({dis[v], v}); } } } for (int i = 1; i <= n; i ++ ){ if (dis[i] != 1e18){ q.push({dis[i], i}); } vis[i] = false; } while(q.size()){ auto t = q.top(); q.pop(); int u = t[1]; if (vis[u]) continue; vis[u] = true; for (auto [w, v] : G[u]){ if (dis[v] > dis[u] + w){ dis[v] = dis[u] + w; q.push({dis[v], v}); } } } for (int i = 2; i <= n; i ++ ){ if (dis[i] == 1e18) cout << "-1"; else cout << dis[i]; cout << " \n"[i == n]; } }; dijkstra(1); return 0; }