概述
很水的一场比赛,快来做前几场比赛的小清新题!!
A
Description
给出两个时间,求它们中点时间。
Solution
把小时和分钟转化成分钟再取中点,再转化回去即可。
Code
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 10;
char a[maxn], b[maxn];
int change(char *a)
{
int h = (a[0] - '0') * 10 + a[1] - '0', m = (a[3] - '0') * 10 + a[4] - '0';
return h * 60 + m;
}
std::string enchange(int mid)
{
std::string s = " ";
int h = mid / 60, m = mid % 60;
s[0] = h / 10 + '0', s[1] = h % 10 + '0', s[2] = ':', s[3] = m / 10 + '0', s[4] = m % 10 + '0';
return s;
}
int main()
{
cin >> a >> b;
int p = change(a), q = change(b);
int mid = (p + q) / 2;
cout << enchange(mid) << endl;
}
B
Description
从 $n$ 个数中每次选两个数,这两个数的和必须为 $k$ 的倍数。问最多能选出多少个数满足条件。
Solution
显然加入一个数模 $k$ 是 $x$,那么他只能和模 $k$ 是 $k-x$ 的数配对。
开一个桶记录一下每种余数的个数然后统计答案即可。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 2e5 + 10;
int a[maxn], b[maxn], k, n;
int main()
{
std::ios::sync_with_stdio(false);
cin >> n >> k;
for (int i = 1, x; i <= n; i++)
cin >> x, b[x % k]++;
int ans = b[0] / 2 * 2;
for (int i = 1; i < k / 2; i++)
ans += std::min(b[i], b[k - i]) * 2;
if (k % 2 == 0)
ans += b[k / 2] / 2 * 2;
else
ans += std::min(b[k / 2], b[k / 2 + 1]) * 2;
cout << ans << endl;
}
C
Description
给 $n$ 个数,让你找出 $m$ 个数,使得这 $m$ 个数中的最大值减去最小值不大于 $5$,求最大的 $m$。
Solution
排序 + 双指针,太水了我都不知道该说什么。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 2e5 + 10;
int a[maxn], n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
std::sort(a + 1, a + 1 + n);
int l = 1, r = 1, ans = 1;
while (l <= n)
{
while (r <= n && a[r] - a[l] <= 5)
r++;
ans = std::max(ans, r - l);
l++;
}
cout << ans << endl;
}
D
Description
给出两个长度为 $n$ 的数组 $a,b$。
你想要创建一个长度为 $n$ 的数组 $c$,且 $c_i=d\times a_i+b_i,i\in[1, n]$,要求你给 $d$ 赋值,使得数组 $c$ 中的 $0$ 的个数最多并输出最多的 $0$ 的个数。
Solution
$$ c_i=d\times a_i+b_i\Rightarrow d=\frac{-b_i}{a_i} $$
可以算出来让每个数变成 $0$ 的 $d$ 是多少,然后看看出现次数最多是多少。
为了避免浮点误差,我们把分子分母约分一下然后放进 map 里。
特判一下本来就是 $0$ 的情况。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
#include <map>
#include <utility>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); }
typedef std::pair<int, int> pii;
const int maxn = 1e6 + 10;
std::map<pii, int> mp;
int a[maxn], b[maxn], n;
int ans;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
for (int i = 1; i <= n; i++)
if (a[i] < 0)
a[i] *= -1, b[i] *= -1;
else if (a[i] == 0)
ans += b[i] == 0;
for (int i = 1; i <= n; i++)
{
if (a[i] == 0)
continue;
int d = gcd(a[i], b[i] < 0 ? -b[i] : b[i]);
a[i] /= d, b[i] /= d;
mp[pii(a[i], b[i])]++;
}
int cnt = 0;
for (auto k : mp)
{
cnt = std::max(cnt, k.second);
}
cout << ans + cnt << endl;
}
E
Description
您是本地大学的教练,有 $n$ 位选手在你这里学习,并且已知第 $i$ 位的能力值为 $a_i$。
现在您需要挑选出若干位选手组成至多 $k$ 支队伍。众所周知,参赛的人数越多,你的大学获胜的概率越大。所以,你需要使得你选出的至多$k$支(至少$1$支)非空队伍的总人数最多。但是,你知道每支队伍中队员们的实力应当差不多,这意味着对于任意一支队伍,不应当存在两名实力值相差超过 $5$ 的选手。所有的队伍都是相互独立的(这意味着我们不考虑来自两只不同队伍的选手的实力值差距)。
可能有的选手不属于任何一支队伍。
您的任务是求出满足以上要求的至多 $k$(至少 $1$)支非空队伍的总人数。
$n,k\leq5000$。
Solution
数据范围告诉我们要 DP。
我们把实力值排个序,显然如果选了一个人,把和他实力值相差小于 $5$ 的人全选上是最优的。
预处理一个 $lst_i$ 表示第 $i$ 个人,上一个实力值比他小超过 $5$ 的人的位置。
设 $f(i,j)$ 表示前 $i$ 个人,已经组了 $j$ 个队伍的参赛总人数。
然后考虑这个人选不选,有: $$ f(i,j)=\max(f(i-1,j),f(lst_i,j-1)+i-lst_i) $$ 前面是不选,后面是选。
直接转移即可,时间复杂度 $O(nk)$。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 5010;
int lst[maxn], f[maxn][maxn], a[maxn], n, k;
int main()
{
std::ios::sync_with_stdio(false);
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
std::sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
{
int pos = i;
while (pos >= 1 && a[i] - a[pos] <= 5)
pos--;
lst[i] = pos;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
f[i][j] = f[i - 1][j];
f[i][j] = std::max(f[i][j], f[lst[i]][j - 1] + i - lst[i]);
}
}
cout << f[n][k] << endl;
}
F1
Description
给出了一个由 $n$ 个顶点和 $m$ 条边组成的无向无权连通图。它保证在给定的图中没有自环或重边。
你的任务是找到这个图的一棵生成树,使得树上点的最大度数尽可能地大。
Solution
很显然我们可以构造出一棵以原图中度数最大的点为根,包括其在原图上所有相邻结点的树。
BFS 构造一下就行。
Code
#include <iostream>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 2e5 + 10;
int n, m, d;
std::vector<int> e[maxn];
inline void add(int x, int y) { e[x].push_back(y), e[y].push_back(x); }
int cnt, vis[maxn], vis2[maxn], used[maxn];
void bfs(int s)
{
std::queue<int> q;
vis2[s] = 1;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (int v : e[x])
{
if (!vis2[v])
cout << x << " " << v << endl, q.push(v), vis2[v] = 1;
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0, x, y; i < m; i++)
cin >> x >> y, add(x, y);
int s = 1;
for (int i = 2; i <= n; i++)
if (e[i].size() > e[s].size())
s = i;
bfs(s);
}
F2
Description
给你一个图,让你构造出一个编号为 $1$ 的点的度数为 $D$ 的树
(保证没有自环和重边)
Solution
我们设这棵树以 $1$ 为根。
一开始想的是假如 $1$ 的一个子树内有一条边连向另一个子树,那么这条边就可以删掉。
感觉很点双啊。。。。。。
后来转念一想,都点双了,我们直接把 $1$ 号点删掉然后看有几个联通块不就能得到能删掉几条边了吗?。。。
这样就能判断出来有解的条件:
- 点 $1$ 的度数不小于 $D$;
- 删掉 $1$ 之后连通块个数不大于 $D$。
可以 DFS 找连通块,用和 F1 类似的 BFS 做法输出答案。
Code
很丑。
#include <iostream>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
const int maxn = 2e5 + 10;
int n, m, d;
std::vector<int> e[maxn];
inline void add(int x, int y) { e[x].push_back(y), e[y].push_back(x); }
int cnt, vis[maxn], vis2[maxn], used[maxn];
void dfs(int x, int p)
{
vis[x] = p;
for (int v : e[x])
if (v != 1 && !vis[v])
dfs(v, p);
}
void bfs()
{
std::queue<int> q;
vis2[1] = 1;
int tot = 0;
for (int i = 0; i < (int)e[1].size(); i++)
if (!used[vis[e[1][i]]])
q.push(e[1][i]), cout << 1 << " " << e[1][i] << endl, vis2[e[1][i]] = 1, used[vis[e[1][i]]] = 1, tot++;
for (int v : e[1])
{
if (!vis2[v])
cout << 1 << " " << v << endl, vis2[v] = 1, tot++, q.push(v);
if (tot == d)
break;
}
while (!q.empty())
{
int x = q.front();
q.pop();
for (int v : e[x])
{
if (!vis2[v])
cout << x << " " << v << endl, q.push(v), vis2[v] = 1;
}
}
}
int main()
{
cin >> n >> m >> d;
for (int i = 0, x, y; i < m; i++)
cin >> x >> y, add(x, y);
for (int i = 2; i <= n; i++)
if (!vis[i])
dfs(i, ++cnt);
if ((int)e[1].size() < d || cnt > d)
{
puts("NO");
return 0;
}
//for (int i = 1; i <= n; i++)
// cout << vis[i] << " ";
//cout << endl;
puts("YES");
bfs();
}