比赛链接:
https://codeforces.com/gym/102769
A. A Greeting from Qinhuangdao
题意:
有 \(r\) 个红球和 \(b\) 个蓝球,拿两个球,问全是红球的概率。
思路:
\(n\) 个球拿两个的方案为 \(C_n^2\)。
求出拿两个红球的方案和拿所有球的方案,除一个公约数即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
int a, b;
cin >> a >> b;
LL p = a * (a - 1) / 2, q = (a + b) * (a + b - 1) / 2;
LL d = __gcd(p, q);
cout << p / d << "/" << q / d << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int T = 1;
cin >> T;
for (int i = 1; i <= T; i ++ ){
cout << "Case #" << i << ": ";
solve();
}
return 0;
}
E. Exam Results
题意:
\(n\) 个学生参加考试,第 \(i\) 个学生好心情的时候能拿 \(a_i\) 分,坏心情的时候能拿 \(b_i\) 分(\(b_i <= a_i\)),当某个学生的成绩 >= 最高分 * \(p\)% 的时候,他能通过考试,问最多能有几个学生通过考试。
思路:
先将所有分数加入 vector 中,然后排序,通过双指针枚举最高分和及格线,当最高分 >= 所有人都是坏心情的时候的最大值时,它才是答案,输出最大值。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
LL n, p;
cin >> n >> p;
vector < pair<LL, int> > v;
LL lim = 0;
for (int i = 0; i < n; i ++ ){
LL a, b;
cin >> a >> b;
v.push_back({a, i});
v.push_back({b, i});
lim = max(lim, b);
}
sort(v.begin(), v.end());
vector <int> cnt(n);
int ans = 0, cur = 0;
for (int i = 0, j = 0; i < 2 * n; i ++ ){
while(j < i && 100 * v[j].first < p * v[i].first){
cnt[v[j].second] -- ;
if (cnt[v[j].second] == 0) cur -- ;
j ++ ;
}
if (cnt[v[i].second] == 0) cur ++ ;
cnt[v[i].second] ++ ;
if (v[i].first >= lim) ans = max(ans, cur);
}
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int T = 1;
cin >> T;
for (int i = 1; i <= T; i ++ ){
cout << "Case #" << i << ": ";
solve();
}
return 0;
}
F. Friendly Group
题意:
有 \(n\) 个人,\(m\) 对关系,表示 \(u\) 和 \(v\) 是朋友,现在选择一些人参加会议,如果某对关系中两个人都参与了会议,可以获得一点分数,如果只有一个人参与了会议,会扣一点分数,参加了几个人会扣几分,问最大能获得多少分。
思路:
现在选择了点 \(u\),考虑选不选 \(v\)。
不选的话,扣一分,因为一对关系中有一个人没参加。
选了的话,加一分,然后扣一分,因为选择了关系,但是多选了一个点,所以得 0 分。
显然,所有连通的点都要选。一个连通块的答案就是连通块中的边减去点。将所有连通块得分大于 0 的加起来就是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
int n, m;
cin >> n >> m;
vector < vector<int> > e(n + 1);
for (int i = 1; i <= m; i ++ ){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
vector <int> vis(n + 1);
int sum, ver;
function<void(int)> dfs = [&](int u){
sum += e[u].size();
ver ++ ;
for (auto v : e[u]){
if (vis[v]) continue;
vis[v] = 1;
dfs(v);
}
};
int ans = 0;
for (int i = 1; i <= n; i ++ ){
if (vis[i]) continue;
sum = ver = 0;
vis[i] = 1;
dfs(i);
ans += max(0, sum / 2 - ver);
}
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int T = 1;
cin >> T;
for (int i = 1; i <= T; i ++ ){
cout << "Case #" << i << ": ";
solve();
}
return 0;
}
G. Good Number
题意:
给定 \(n\) 和 \(k\),判断不超过 \(n\) 的数中满足 \(\lfloor \sqrt[k]x\rfloor\) 能整除 \(n\) 的数的数量。
思路:
逆过来想,\([x^k, x^{k + 1})\) 的数中开了 \(k\) 次根号之后,都是 \(x\),即这个区间中 \(x\) 的倍数都是可以的,跑个暴力就行。
注意两个特殊情况,\(k = 1\) 的时候,所有数都是可以的,\(k >= 30\) 的时候,开完根号之后都是 1,所有数也都是可以的。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
LL n, k;
cin >> n >> k;
if (k == 1 || k >= 30){
cout << n << "\n";
}
else{
LL ans = 0, x = 1;
for (int i = 2; x <= n; i ++ ){
LL y = 1;
for (int j = 1; j <= k; j ++ )
y = min(y * i, n + 1);
ans += (y - 1) / (i - 1) - (x - 1) / (i - 1);
x = y;
}
cout << ans << "\n";
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int T = 1;
cin >> T;
for (int i = 1; i <= T; i ++ ){
cout << "Case #" << i << ": ";
solve();
}
return 0;
}
K. Kingdom's Power
题意:
有一棵树,根节点有无数军队,每次可以让一支军队向相邻的节点进发,当军队到达一个节点的时候,这个节点就被攻克,问最少移动多少次可以让攻克。
思路:
每个节点的军队只可能从根节点或者另一个叶节点过来,于是对每个节点按照深度排序,优先走深度小的节点。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6 + 10;
int dep[N], mxdep[N];
void solve(){
int n;
cin >> n;
vector < vector<int> > e(n + 1);
for (int v = 2; v <= n; v ++ ){
int u;
cin >> u;
e[u].push_back(v);
}
function<void(int, int)> dfs1 = [&](int u, int depth){
mxdep[u] = dep[u] = depth;
for (auto v : e[u]){
dfs1(v, depth + 1);
mxdep[u] = max(mxdep[u], mxdep[v]);
}
sort(e[u].begin(), e[u].end(), [](int a, int b){
return mxdep[a] < mxdep[b];
});
};
dfs1(1, 0);
int pre = 0, ans = 0;
function<void(int, int)> dfs2 = [&](int u, int fa){
if (u != 1){
if (!pre) ans += dep[u];
else ans += min(dep[u], dep[pre] - dep[fa] + 1);
pre = u;
}
for (auto v : e[u]){
if (v == fa) continue;
dfs2(v, u);
}
};
dfs2(1, 0);
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int T = 1;
cin >> T;
for (int i = 1; i <= T; i ++ ){
cout << "Case #" << i << ": ";
solve();
}
return 0;
}