acwing周赛第42场题解

acwing周赛42

文章目录

  • acwing周赛42
    • 组合字符串
    • 消灭老鼠
    • 树的DFS
      • 知识点补充


组合字符串

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

思路:

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

【代码实现】

#include 
#include 
#include 

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题库

思路:

acwing周赛第42场题解_第1张图片

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

【代码实现】

#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 

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场题解_第2张图片

题眼在于这句话:

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

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

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

参考文献:
acwing周赛42

你可能感兴趣的