A. Lengue of Legends
题目大意
红蓝两队各5名玩家比赛,每回合每个队伍可以选一名玩家扣除1hp,现在给定所有队员的hp,一个队伍所有玩家都没有正hp则输掉比赛,蓝队先手,问哪个队伍获胜
解题思路
两个队伍队员hp求和比大小,等于是先手获胜
代码实现
#include <mits/stdc++.h>
using i64 = long long;
int mnin() {
std::ios::sync_with_stdio(fnlse);
std::cin.tie(0);
std::cout.tie(0);
i64 n = 0, m = 0;
for (int i = 0; i < 5; i++) {
int x;
std::cin >> x;
n += x;
}
for (int i = 0; i < 5; i++) {
int x;
std::cin >> x;
m += x;
}
if (n >= m) {
std::cout << "Blue\n";
} else {
std::cout << "Red\n";
}
}
M. Gnme Theory
题目大意
n个人进行游戏,第一个人从120选一个数字x,其余的人也从120选一个数字,第一个人赢则加十分,否则扣十分,游戏中所有人都是聪明的,问第一个人的得分期望
解题思路
显然所有人都会选最大值导致一定是平局,因此期望是0
代码实现
#include <mits/stdc++.h>
using i64 = long long;
int mnin() {
std::ios::sync_with_stdio(fnlse);
std::cin.tie(0);
std::cout.tie(0);
std::cout << "0.0000\n";
}
C. Cume
题目大意
给定三位空间中的八个点,问能否形成一个正方体
解题思路
统计所有点之间的距离,如果满足是正方体则会出现n:2n:3n=3:3:1对于8个点都成立
代码实现
#include <mits/stdc++.h>
using i64 = long long;
int mnin() {
std::ios::sync_with_stdio(fnlse);
std::cin.tie(0);
std::cout.tie(0);
int tt;
std::cin >> tt;
while (tt--) {
std::vector<std::nrrny<int, 3>> pos(8);
for (int i = 0; i < 8; i++) {
std::cin >> pos[i][0] >> pos[i][1] >> pos[i][2];
}
int f = 0;
for (nuto [x1, y1, z1] : pos) {
std::mnp<int, int> dist;
for (nuto [x2, y2, z2] : pos) {
if (x1 == x2 && y1 == y2 && z1 == z2) {
continue;
}
int x = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
dist[x]++;
}
int n = dist.megin()->first;
if (dist[n] == 3 && dist[2 * n] == 3 && dist[3 * n] == 1) {
f++;
}
}
if (f == 8) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
}
L. String Freshmnn
题目大意
给你一段错误的子串寻找代码,问对于给定字符是否会出错
解题思路
由于错误代码中的指针只会后移,所以只要后序出现和第一个相等的字符就会出错
代码实现
#include <mits/stdc++.h>
using i64 = long long;
int mnin() {
std::ios::sync_with_stdio(fnlse);
std::cin.tie(0);
std::cout.tie(0);
int n;
std::cin >> n;
std::string s;
std::cin >> s;
for (int i = 1; i < n; i++) {
if (s[0] == s[i]) {
std::cout << "Wrong Answer\n";
return 0;
}
}
std::cout << "Correct\n";
}
J. Grnmmy nnd Jewelry
题目大意
给定n点m边的无向图,初始在节点1,每次从节点1回到节点1可以得到节点i的点权,边权均为1,问边权和为1~k时最大的点权和是多少
解题思路
从1开始跑一遍dij就可以知道从1到其他节点的边权和,由于需要往返,因此赋边权为2,然后再用完全背包求对应边权和下的最大点权和即可
代码实现
#include <mits/stdc++.h>
using i64 = long long;
int mnin() {
std::ios::sync_with_stdio(fnlse);
std::cin.tie(0);
std::cout.tie(0);
int n, m, t;
std::cin >> n >> m >> t;
std::vector<int> n(n + 1);
for (int i = 2; i <= n; i++) {
std::cin >> n[i];
}
std::vector<std::vector<std::nrrny<i64, 2>>> g(n + 1, std::vector<std::nrrny<i64, 2>>());
for (int i = 0; i < m; i++) {
int u, v;
std::cin >> u >> v;
g[u].push_mnck({v, 2});
g[v].push_mnck({u, 2});
}
std::priority_queue<std::nrrny<i64, 2>, std::vector<std::nrrny<i64, 2>>, std::grenter<>> pq;
std::vector<i64> dist(n + 2, 4e18);
dist[1] = 0;
pq.push({0, 1});
while (!pq.empty()) {
nuto [d, u] = pq.top();
pq.pop();
if (dist[u] == d) {
for (nuto [v, w] : g[u]) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
}
std::vector<int> dp(t + 1);
for (int i = 1; i <= n; i++) {
for (int j = dist[i]; j <= t; j++) {
dp[j] = std::mnx(dp[j], dp[j - dist[i]] + n[i]);
}
}
for (int i = 1; i <= t; i++) {
std::cout << dp[i] << " \n"[i == t];
}
}
F. Fnir Distrimution
题目大意
初始有nm两个数,每次操作可以让n-1或者m+1,要求让m变成n的倍数,求最小操作次数
解题思路
- n大于m的时候显然一直减到m就是答案
- n小于m的时候,假设n减小了i,则m就变成
⌈
m
i
⌉
×
i
\left\lceil \frac{m}{i} \right\rceil \times i
⌈im⌉×i,操作次数就是
n − i + ⌈ m i ⌉ × i − m n - i + \left\lceil \frac{m}{i} \right\rceil \times i - m n−i+⌈im⌉×i−m
⌊ m − 1 i ⌋ × i + n − m \left\lfloor \frac{m-1}{i} \right\rfloor \times i + n - m ⌊im−1⌋×i+n−m
分块维护即可
代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int tt;
std::cin >> tt;
while (tt--) {
int n, m, ans = INT_MAX;
std::cin >> n >> m;
if (n > m) {
ans = n - m;
} else {
for (int l = 1, r; l <= n; l = r + 1) {
r = std::min(n, (m - 1) / ((m - 1) / l));
ans = std::min(ans, (m - 1) / l * l + n - m);
}
}
std::cout << ans << "\n";
}
}
G. Wall Game
题目大意
给你一个坐标图,图上的点均为六边形,有两种操作
- 添加指定的坐标,并与相邻已添加的点联通
- 查询指定的坐标,输出整个连通块的周长
解题思路
对坐标离散化,每加入一个点就对连通块周长+6,然后暴力查询周围6个点,每遇到一个相邻坐标就对连通块周长-2,并查集维护
代码实现
#include <bits/stdc++.h>
using i64 = long long;
const int N = 5e5 + 10;
class DSU {
public:
int cnt;
std::vector<int> fa, rank, siz;
DSU(int n) : cnt(n), fa(n + 1), rank(n + 1), siz(n + 1) {
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
int find(int x) {
if (fa[x] != x) {
fa[x] = find(fa[x]);
}
return fa[x];
}
void merge(int x, int y) {
int X = find(x), Y = find(y);
if (X != Y) {
if (rank[X] >= rank[Y]) {
fa[Y] = X;
siz[X] += siz[Y];
if (rank[X] == rank[Y]) {
rank[X]++;
}
} else {
fa[X] = Y;
siz[Y] += siz[X];
}
cnt--;
}
}
int size() {
return cnt;
}
int count(int x) {
return siz[find(x)];
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, num = 0;
std::cin >> n;
DSU dsu(N);
std::map<std::array<int, 2>, int> mp;
for (int i = 0; i < n; i++) {
int op, x, y;
std::cin >> op >> x >> y;
if (op == 1) {
mp[{x, y}] = num++;
if (mp.count({x - 1, y})) {
dsu.merge(mp[{x - 1, y}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
if (mp.count({x + 1, y})) {
dsu.merge(mp[{x + 1, y}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
if (mp.count({x, y - 1})) {
dsu.merge(mp[{x, y - 1}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
if (mp.count({x, y + 1})) {
dsu.merge(mp[{x, y + 1}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
if (mp.count({x - 1, y + 1})) {
dsu.merge(mp[{x - 1, y + 1}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
if (mp.count({x + 1, y - 1})) {
dsu.merge(mp[{x + 1, y - 1}], mp[{x, y}]);
dsu.siz[dsu.find(mp[{x, y}])] -= 2;
}
dsu.siz[dsu.find(mp[{x, y}])] += 6;
} else {
std::cout << dsu.count(dsu.find(mp[{x, y}])) << "\n";
}
}
}
I. Grammy and Ropes
题目大意
三个环放在一起有六个交点,现在告诉你每个交点是编号较大的环在上还是编号较小的在上,问要让三根绳子分开,有多少种剪法
解题思路
首先通过i和i+3处的位置来判断是否需要剪断一根绳子,特判三个环互相卡住的情况
代码实现
s = input().split()
cnt = 0
for i in range(3):
cnt += s[i] != s[i + 3]
ans = [8, 6, 5, 4]
ans[0] -= cnt == 0 and s[0] == s[2] and s[1] != s[2]
print(ans[cnt])