acwing周赛第42场题解

本文详细解析了AcWing周赛42中的三道题目,包括组合字符串问题的枚举解法,消灭老鼠问题的数学与集合判重思路,以及树的DFS遍历及其应用。通过具体代码实现,阐述了如何在有限数据范围内找到最小组合字符串,如何利用欧几里得算法简化向量并计算数量,以及如何在树的DFS中快速查询节点信息。文章还补充了邻接表在图论问题中的不同实现方式。
摘要由CSDN通过智能技术生成

acwing周赛42


组合字符串

【题目链接】4308. 组合字符串 - AcWing题库

思路:

数据范围比较小,枚举两个串的前缀拼接后一一比较即可,最终最小的即为答案。

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int main()
{
    
    string a, b;
    cin >> a >> b;
    
    string res(20, 'z');
    for (int i = 1; i <= a.size(); i ++ )
        for (int j = 1; j <= b.size(); j ++ )
        {
            res = min(res, a.substr(0, i) + b.substr(0, j));
        }
    cout << res;    
    
    return 0;
}

消灭老鼠

【题目链接】4309. 消灭老鼠 - AcWing题库

思路:

在这里插入图片描述

知识点:数学:gcd + 直线的表示 + 集合判重

【代码实现】

#include <iostream>
#include <cstring>
#include <set>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;

int gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    int n, x0, y0;
    cin >> n >> x0 >> y0;
    
    set<PII> S;// 判重
    while (n -- )
    {
        int x, y;
        cin >> x >> y;
        x -= x0, y -= y0;// 向量
        
        // 化简
        int d = gcd(x, y);
        x /= d, y /= d;
        if(x < 0) x = -x, y = -y; // 特判
        S.insert({x, y}); // 用set集合判重
    }
    
    cout << S.size();
    
    return 0;
}

树的DFS

【题目链接】4310. 树的DFS - AcWing题库

树的前序遍历(dfs深搜顺序)

思路:

1.以某一个节点为根节点的子树的所有儿子在dfs序中是连续的一段
2.用p[i]存储每一个节点在dfs序中的下标,用q[i]存储dfs序中下表为i的节点值,二者是一组映射,随着dfs的过程逐渐更新
3.为了快速判断是否有解,需要定义sz数组,存储以某一个节点为根节点的子树的元素个数
(若size[i] < k说明无解)

查询以u为节点的子树的第k个遍历的节点:q[p[u] + k - 1](该点位置p[u] + k - 1)

注意:本题树的节点存储是按照顺序的,且从第2点开始存储

【代码实现】

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 2e5 + 10;
int q[N], p[N], sizes[N];
vector<int> g[N];
int n, m;
int top;

void dfs(int u)
{
    sizes[u] = 1;// 初始大小
    q[top] = u, p[u] = top;// 记录值 和值的位置
    top ++;
    
    for(auto v : g[u])// 遍历u节点的所有出边节点
    {
        dfs(v);// 层序遍历(dfs)
        sizes[u] += sizes[v]; // 记录以u为根的子树的大小
    }
    
}

int main()
{
    cin >> n >> m;
    for (int i = 2; i <= n; i ++ )// 按顺序存储节点信息
    {
        int t;// t为节点i的父节点
        cin >> t;
        g[t].push_back(i);// t --> i
        
    }
    
    dfs(1);
    
    while (m -- )
    {
        int u, k;
        cin >> u >> k;
        if(sizes[u] < k) puts("-1");
        else cout << q[p[u] + k - 1] << endl;
    }
    
    return 0;
}

知识点补充

【转载详细请见】:两种邻接表写法的差异 - AcWing

一般图论问题的邻接表:

int h[N], e[M], w[M], ne[M], idx;

void add(int a, int b, int c)  // 添加一条边a->b,边权为c
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

本题邻接表的写法:

vector<int> h[N];

对于本题4310. 树的DFS - AcWing题库

先来一张图解释一下两种邻接表的差异:

在这里插入图片描述

题眼在于这句话:

我们规定,当遍历(或回溯)到某一节点时,下一个遍历的目标应该是它的未经遍历的子节点中编号最小的那一个子节点。

即题目是按照从小到大的方式插入点的,也希望我们从小到大遍历点

如果没有顺序的要求,当然是两种都可以拉.゚ヽ(。◕‿◕。)ノ゚

参考文献:
acwing周赛42

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值