Educational Codeforces Round 104 (Rated for Div. 2) A-E 个人题解
1487A. Arena
n 个 Hero,分别有 \(a_i\) 的初始等级。每次两个 Hero 战斗时:等级相同无影响,否则等级高的英雄等级+1。直到某个英雄等级到了 \(100^{500}\)游戏结束。问有多少个英雄最后可能获胜。
Solution
只要所有英雄等级不是相同,那么必有 \(n - b_0\)个 Hero 获胜(\(b_0 代表等级最低的个数\))
Code
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
for (cin >> _; _--;) {
int n;
cin >> n;
vector<ll> a(n);
for (auto& x : a) cin >> x;
sort(a.begin(), a.end());
int cnt = n, i = 0;
while (a[i] == a[i + 1] && i < n) i++;
if (i == n) {
cout << 0 << "\n";
continue;
}
cout << n - count(a.begin(), a.end(), a[0]) << "\n";
}
return 0;
}
1478B. Cat Cycle
有一个\(n\)个点的圆环。A在 \(n\) 号点,B在 \(1\) 号点。A逆时针走,B顺时针走。如果A和B下一步是一个点,那么A走一步,B走两步。问经过 \(K\) 步后B在几号点
Solution
看了很久,发现是奇偶数问题,\(n\) 为偶数不会碰到一起,奇数个点时 B 多走 \(\frac{k}{n / 2}\) 步
Code
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
for (cin >> _; _--;) {
ll n, k;
cin >> n >> k;
k--; // 第一秒
if (n & 1) k += (k / (n / 2)); // 模拟奇数个点,k的变化
k++, k %= n;
cout << (k == 0 ? n : k) << "\n";
}
return 0;
}
1478C. Minimum Ties
\(n\) 支队伍要两两对战,平局各加一分,获胜加 3 分,失败无影响。请安排这些对局的结果使得最终所有人的分相等而且平局的数量尽可能少
Solution
显然总共有 \(n*(n-1)/2\) 局,如果全是非平局,那么一人 \((n-1)/2\)局,那么只有在 \(n\) 是奇数的情况下成立。不然必定有平局产生。
然后就按照每个人被分到多少局进行分配就好了。
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
int n, i, j, k;
for (cin >> n; cin >> n;)
for (i = 0; i < n; i++)
for (j = i + 1; k = (j - i) * 2, j < n; j++)
cout << (k == n ? 0 : k < n ? 1 : -1) << ' ';
return 0;
}
1478D. Pythagorean Triples
寻找三元组(a,b,c)满足 \(c^2 = a^2 + b^2\) and \(c = a^2 - b\)
Solution
两个算式联立:\(a^2 = 2 * n + 1\) and \(c = b + 1\)
最后算出个:\((ll)((sqrt(2 * n - 1) - 1) / 2)\)
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
for (cin >> _; _--;) {
ll n;
cin >> n;
cout << (ll)((sqrt(2 * n - 1) - 1) / 2) << "\n";
}
return 0;
}
1478E. Cheap Dinner
给定四个种类的菜各自的价格,给定一些关系:第一种菜中的某一种不能同时和第二种菜中的某一种一起被选中,然后2-nd和3-th,3-rd和4-th。
问四种菜中各择一的最小代价。
Solution
如果单考虑前两种,那么对于第二种菜中的所有菜,可以通过不同时被选中关系得到自己的最小代价(或者不能),把这个代价移到第二种菜上,2-nd和3-rd的菜之间的转移等价于1-st和2-nd之间的转移。一种类似DP转移的思想。代码实现方面就用multiset乱搞,每次考虑两种关系的时候,先把当前点所不连通的点删掉,最后再加回来,可以这么做的原因是我只要考虑值,不需要考虑具体的关系。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int arr[5][maxn], dp[5][maxn];
int nums[5];
vector<int> vv[5][maxn];
void solve() {
for (int i = 1; i <= 4; ++i) scanf("%d", &nums[i]);
for (int i = 1; i <= 4; ++i) {
for (int j = 1; j <= nums[i]; ++j) {
scanf("%d", &arr[i][j]);
}
}
for (int i = 2; i <= 4; ++i) {
int m;
scanf("%d", &m);
for (int j = 1, x, y; j <= m; ++j) {
scanf("%d %d", &x, &y);
vv[i][y].push_back(x);
}
}
for (int i = 1; i <= nums[1]; ++i) {
dp[1][i] = arr[1][i];
}
for (int i = 2; i <= 4; ++i) {
multiset<int> ss;
for (int l = 1; l <= nums[i - 1]; ++l) {
if (dp[i - 1][l] != -1) ss.insert(dp[i - 1][l]);
}
for (int j = 1; j <= nums[i]; ++j) {
for (int k = 0; k < vv[i][j].size(); ++k) {
int v = vv[i][j][k];
if (dp[i - 1][v] != -1) ss.erase(ss.find(dp[i - 1][v]));
}
if (ss.size() == 0)
dp[i][j] = -1;
else
dp[i][j] = *ss.begin() + arr[i][j];
for (int k = 0; k < vv[i][j].size(); ++k) {
int v = vv[i][j][k];
if (dp[i - 1][v] != -1) ss.insert(dp[i - 1][v]);
}
}
}
int ans = -1;
for (int i = 1; i <= nums[4]; ++i) {
if (dp[4][i] != -1) {
if (ans == -1 || ans > dp[4][i]) ans = dp[4][i];
}
}
printf("%d\n", ans);
}
int main() {
int t = 1;
// scanf("%d", &t);
while (t--) solve();
return 0;
}