Codeforces Round #875 (Div. 2) A-D

比赛链接

A

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
cout << n - x + 1 << " \n"[i == n];
}
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

B

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int lena[400007], lenb[400007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= 2 * n;i++) lena[i] = lenb[i] = 0;
int pre = 0, len = 0;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
if (x != pre) {
lena[pre] = max(lena[pre], len);
len = 0;
pre = x;
}
len++;
}
lena[pre] = max(lena[pre], len);
len = 0;
pre = 0;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
if (x != pre) {
lenb[pre] = max(lenb[pre], len);
len = 0;
pre = x;
}
len++;
}
lenb[pre] = max(lenb[pre], len);
int ans = 0;
for (int i = 1;i <= 2 * n;i++) ans = max(ans, lena[i] + lenb[i]);
cout << ans << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

C

题意

一棵树有 n 个节点,一开始只有根节点 1

现在给出加边的顺序,每次操作按顺序从头到尾依次加边。

一次操作中,当且仅当一条边还没被加,且一个端点已经存在,才能加这条边。

问要最少操作几次,所有边才能都被加入。

题解

知识点:树形dp,DFS。

可以用树型dp求出每个点出现需要的最少操作次数。

点的出现时间取决于边的顺序,我们将边的顺序记录到边权中,dfs过程中将边权当作孩子的出现时间。

若一个点出现时间比它孩子出现时间要晚,那么它孩子出现需要的操作次数就是它的操作次数加 1 ,否则可以在同一次操作中处理完。

fu 表示节点 u 出现需要的最少操作次数, rku 表示节点 u 的出现时间,转移即上述所说。

最后答案为 fu 的最大值。

时间复杂度 O(n)

空间复杂度 O(n)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
vector<pair<int, int>> g[200007];
int rk[200007], f[200007];
void dfs(int u, int fa) {
for (auto [v, w] : g[u]) {
if (v == fa) continue;
rk[v] = w;
f[v] = f[u] + (w < rk[u]);
dfs(v, u);
}
}
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) g[i].clear();
for (int i = 1;i <= n - 1;i++) {
int u, v;
cin >> u >> v;
g[u].push_back({ v,i });
g[v].push_back({ u,i });
}
rk[1] = n;
dfs(1, 0);
cout << *max_element(f + 1, f + n + 1) << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

D

题意

给定长度为 n 的数组 a,b ,求出所有满足 aiaj=bi+bj(1i<jn)(i,j) 对数。

题解

知识点:数学,枚举。

注意到 1ai,bin(1in) ,因此 aiaj2n ,即 min(ai,aj)2n 。此时,我们设 ajai ,那么 aj2n

因此,我们先将 ai,bi 打包,以 a 为关键字从小到大排序,这是为了之后从左到右枚举 ai,bi 时,保证满足 ajai(1j<i) 这个条件,此时 aj 的范围才是 [1,2n]

随后,我们枚举 A[1,2n] ,作为一轮枚举中 aj 满足的值。接下来,从左到右枚举 ai,bi ,有 B=Aaibi ,其中 B 就是在 aj=A 时我们希望的 bj ,而 ai,bi 的贡献即为 1j<i 满足 aj=A 的位置中,出现过的 bj=B 的位置数。

因此,我们在过程中记录 1j<i 满足 aj=A 的位置中,出现过的 bj 的个数 cntbj。那么,当 1Bn 时, cntB 即为 ai,bi 的贡献。

时间复杂度 O(nn)

空间复杂度 O(n)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
pair<int, int> c[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++)cin >> c[i].first;
for (int i = 1;i <= n;i++)cin >> c[i].second;
sort(c + 1, c + n + 1);
ll ans = 0;
for (int A = 1;A * A <= 2 * n;A++) {
vector<int> cnt(n + 1);
for (int i = 1;i <= n;i++) {
auto [a, b] = c[i];
int B = A * a - b;
if (1 <= B && B <= n) ans += cnt[B];
if (a == A) cnt[b]++;
}
}
cout << ans << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
posted @   空白菌  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2022-07-16 CF590C Three States
2022-07-16 NC235247 Sramoc问题
2022-07-16 NC24605 [USACO 2011 Ope S]Corn Maze
2022-07-16 NC19975 [HAOI2008]移动玩具
2022-07-16 NC17872 CSL的校园卡
2022-07-16 NC15445 wyh的吃鸡
2022-07-16 NC15136 迷宫
点击右上角即可分享
微信分享提示