【Acwing 周赛复盘】第92场周赛复盘(2023.2.25)

【Acwing 周赛复盘】第92场周赛复盘(2023.2.25)

周赛复盘 ✍️

本周个人排名:1293/2408

AC情况:1/3

这是博主参加的第七次周赛,又一次体会到了世界的参差(这次周赛记错时间了,以为 19:15 开始,不然 T3 应该也能 AC,就差一点 😂)

T1 签到题。✅

T2 没啥思路,就跳过去做 T3 了。❌ (经过y总讲解后,发现这是一道非常精妙,涉及树的前序遍历的递归题,值得反复咀嚼)

T3 题意有点绕,但是读明白之后,就是一道并查集的变形题目,但是融合了一点贪心思想。在看样例1时,以为只要输出最大集合的元素个数就行了;但是模拟样例2时发现,不对啊,这后面几个输出怎么和自己想的不一样呢。于是就开始模拟样例2的过程,但是中途却卡壳了许久,有几个输出一直没想明白。等完全想明白时,比赛时间已经到了。❌

希望未来也能继续努力,紧跟大佬们的步伐,继续加油 💪

image-20230225212919384


周赛信息 📚

时间:2023年 2 月 25 日 19:00-20:15

竞赛链接https://www.acwing.com/activity/content/2908/

y总直播间http://live.bilibili.com/21871779

y总录播讲解视频【AcWing杯 - 第 92 场周赛讲解】


题目列表 🧑🏻‍💻

题目名称原题链接视频讲解难度
AcWing 4864. 多边形原题链接视频链接简单 🟢
AcWing 4865. 有效类型原题链接视频链接中等 🟡
AcWing 4866. 最大数量原题链接视频链接困难 🔴

题解 🚀

【题目A】多边形

【题目描述】

如果一个正多边形的边数 n n n 能被 4 4 4 整除,那么就称该正多边形是美丽的。

现在,给定一个正多边形的边数 n n n,请你判断它是否是美丽的。

【输入】

第一行包含整数 T T T,表示共有 T T T 组测试数据。

每组数据占一行,包含一个整数 n n n

【输出】

每组数据输出一行结果,如果给定正多边形是美丽的,则输出 YES,否则输出 NO

【数据范围】

3 3 3 个测试点满足 1 ≤ T ≤ 10 1 \le T \le 10 1T10

所有测试点满足 1 ≤ T ≤ 1 0 4 1 \le T \le 10^4 1T104 3 ≤ n ≤ 1 0 9 3 \le n \le 10^9 3n109

【输入样例1】
4
3
4
12
1000000000
【输出样例1】
NO
YES
YES
YES
【原题链接】

https://www.acwing.com/problem/content/4867/


【题目分析】

签到题。

【周赛现场 AC 代码】✅
#include<bits/stdc++.h>

using namespace std;

int T, x;

int main() {
    cin >> T;
    while (T--) {
        cin >> x;
        if (x % 4 == 0)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}


【题目B】有效类型

【题目描述】

在本题中,关于有效类型字符串,具体定义如下:

  • int 是有效类型字符串。
  • 如果字符串 X 和字符串 Y 都是有效类型字符串,则 pair<X,Y> 是有效类型字符串。

现有一行若干个单词,每个单词要么是 pair,要么是 int,并且其中 int 的数量恰好为 n n n 个。

你可以在不改变单词顺序的前提下,在这一行中任意添加 <>, 符号。

你的任务是构造出一个有效类型字符串。

输出这个有效类型字符串。

注意:

  1. 有效类型字符串中 不含 空格或其它多余字符。
  2. 可以证明如果存在满足条件的有效类型字符串,那么它一定是唯一的。
  3. 如果不存在满足条件的有效类型字符串,输出 Error occurred 即可。
【输入】

第一行包含整数 n n n,表示给定单词中 int 的数量。

第二行包含若干个单词,每个单词要么是 pair,要么是 int

【输出】

输出满足条件的有效类型字符串,如果不存在,则输出 Error occurred

注意,有效类型字符串中 不含 空格或其它多余字符。

【数据范围】

6 6 6 个测试点满足: 1 ≤ n ≤ 5 1 \le n \le 5 1n5
所有测试点满足: 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105,输入的总单词数量不超过 1 0 5 10^5 105,输入的 int 数量恰好为 n n n

【输入样例1】
3
pair pair int int int
【输出样例1】
pair<pair<int,int>,int>
【输入样例2】
1
pair int
【输出样例2】
Error occurred
【原题链接】

https://www.acwing.com/problem/content/4868/


【题目分析】

递归构建 前序遍历的 pair 二叉树,代码十分精妙(详见代码注释)

这种递归的解题方式 值得反复咀嚼

详细讲解见y总视频:https://www.acwing.com/video/4637/

image-20230226202730027

【复盘后的优化代码】✅
//
// Created by Ricky X on 2023/2/24.
//

#include<bits/stdc++.h>

using namespace std;
int n;
string str, ans;

bool dfs() {
    // 当前有字符可以读入
    if (cin >> str && str != "") {
        // 当前读入字符串为pair,则需要构建左右子树
        if (str == "pair") {
            ans += "pair<";
            if (!dfs()) return false; // 无法构建左子树,返回false
            ans += ",";
            if (!dfs()) return false; // 无法构建右子树,返回false
            ans += ">";
            return true;
        } else if (str == "int") {  // 读入为int,直接返回true
            ans += "int";
            return true;
        }
    } else {  // 当前没有字符读入,无法构建,返回false
        return false;
    }
}

int main() {
    cin >> n;
    // dfs()的作用是读入一个字符串,并且将其作为根结点,判断能否建立一颗树
    // dfs()返回true,说明当前读入的字符串可以构建一颗树
    // dfs()返回false,说明当前读入的字符串不可以构建一棵树
    // 不可以构建的情况:1.字符串读完了;2.读入pair,但是无法构建左右子树

    // dfs()构建成功,但是还有字符串读入,就会有多棵树,舍去该情况
    // 当且仅当dfs()构建成功,且没有字符串读入时,才能输出答案
    // 答案存储到字符串ans中
    bool flag = dfs();
    if (flag && cin >> str) flag = false;

    // 输出结果
    if (!flag) cout << "Error occurred" << endl;
    else cout << ans << endl;

    return 0;
}
【周赛现场 AC 代码】

现场未 AC



【题目C】最大数量

【题目描述】

一个无向图有 n n n 个点,编号 1 ∼ n 1∼n 1n

这些点之间没有任何边。

给定 d d d 个需求,编号 1 ∼ d 1∼d 1d

其中,第 i i i 个需求是让点 x i x_i xi 和点 y i y_i yi 连通。

需求可能存在重复。

在本题中,你需要依次解决 d d d 个问题,编号 1 ∼ d 1∼d 1d

其中,第 i i i 个问题是,请你在图中添加恰好 i i i 条无向边(不能添加重边和自环),使得:

  1. i i i 个需求都得到满足。
  2. 所有点的度的最大值尽可能大。

对于每个问题,你不需要输出具体方案,你只需要输出度的最大可能值。

注意:

  1. 如果点 a a a 和点 b b b 之间存在路径,则称点 a a a 和点 b b b 连通。
  2. 图中与点 a a a 关联的边数,称为点 a a a 的度。
  3. d d d 个问题之间是相互独立的,每个问题的答案都必须独立计算。
【输入】

第一行包含两个整数 n , d n,d n,d

接下来 d d d 行,其中第 i i i 行包含两个整数 x i , y i x_i,y_i xi,yi,表示第 i i i 个需求是让点 x i x_i xi 和点 y i y_i yi 连通。

【输出】

d d d 行,其中第 i i i 行输出第 i i i 个问题中,度的最大可能值。

【数据范围】

前三个测试点满足, 2 ≤ n ≤ 10 2 \le n \le 10 2n10

所有测试点满足, 2 ≤ n ≤ 1000 2 \le n \le 1000 2n1000 1 ≤ d ≤ n − 1 1 \le d \le n−1 1dn1 1 ≤ x i , y i ≤ n 1 \le x_i,y_i \le n 1xi,yin x i ≠ y i x_i \ne y_i xi=yi

【输入样例1】
7 6
1 2
3 4
2 4
7 6
6 5
1 7
【输出样例1】
1
1
3
3
3
6
【输入样例2】
10 8
1 2
2 3
3 4
1 4
6 7
8 9
8 10
1 4
【输出样例2】
1
2
3
4
5
5
6
8
【原题链接】

https://www.acwing.com/problem/content/4869/


【题目分析】

并查集 + 贪心(菊花图)

具体讲解见y总视频:https://www.acwing.com/video/4638/

image-20230226093749980

【复盘后的优化代码】✅
//
// Created by Ricky X on 2023/2/24.
//

#include<bits/stdc++.h>

using namespace std;
const int N = 1010;
int pre[N], sum[N];
int n, d, a, b, op; // op是可以额外连接的操作次数

// 并查集初始化
void init() {
    for (int i = 1; i <= n; i++) pre[i] = i, sum[i] = 1;
}

// 查找元素x的祖先
int find(int x) {
    if (pre[x] != x) pre[x] = find(pre[x]);
    return pre[x];
}

// 合并两个集合
void join(int a, int b) {
    int x = find(a);
    int y = find(b);
    if (x != y) pre[x] = y, sum[y] += sum[x];
    else op++; // 额外连接操作数+1
}

// 查询
void solve() {
    // 将当前集合的大小存入vector
    vector<int> v;
    v.clear();
    for (int i = 1; i <= n; i++)
        if (pre[i] == i)
            v.push_back(sum[i]);
    sort(v.begin(), v.end(), greater<int>());

    // 通过op次操作,把前op个元素数量最大的集合合并
    int res = v[0]; // 第一个最大的集合是不用合并的
    for (int i = 1; i <= op; i++) {
        res += v[i];
    }
    cout << res - 1 << endl;
}

int main() {
    ios::sync_with_stdio(false);  //cin读入优化
    cin.tie(0);

    cin >> n >> d;
    init();
    for (int i = 1; i <= d; i++) {
        cin >> a >> b;
        join(a, b);
        solve();  // 求解当前问题i的答案
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值