acwing41届周赛,爆0笔记

第一次参加周赛,爆0,感受到了自己是有多菜,下决心下周不可能爆0,下面是周赛题目笔记。

1.组合字符串

先解释一下什么是非空前缀:
就相当于从一个字符串中截取一段字符串,这个字符串必须从整个字符串的开头开始截取,

比如 abcdef,所有的非空前缀有:
a,ab,abc,abcd,abcde,abcdef
然后我们直接枚举两个字符串从前面取出来的前缀,组合起来然后求最小值即可。

截取字符串那么我们需要用到substr函数,关于substr函数

因为数据比较小,从0到10,那么我们可以直接暴力枚举

#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 ++ ) //枚举两个字符串截取前缀的长度,不能为0。
            res = min(res, a.substr(0, i) + b.substr(0, j));//第一个参数是起始位置,第二个是长度。

    cout << res << endl;
    return 0;
}

消灭老鼠

这题其实就是通过求 激光枪所在的点(x0,y0)与老鼠所在的点所成的直线的斜率,然后通过斜率来存直线,在同一条直线上的老鼠,这个直线斜率相同,所以直线数量就是至少射击次数。

set自带去重功能所以我们这里用set来存,

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

#define x first
#define y second

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});
    }

    cout << S.size() << endl;
    return 0;
}

树的DFS

给定一棵 n 个节点的树。

节点的编号为 1∼n,其中 1 号节点为根节点,每个节点的编号都大于其父节点的编号。

现在,你需要回答 q 个询问。

每个询问给定两个整数ui,ki。

我们希望你用 DFS(深度优先搜索)算法来遍历根节点为 ui 的子树。

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

每一棵子树在dfs序中一定是连续的一段

解题步骤

1.用邻接表存边。
2.用dfs,记录下dfs的序列,顺便算一下以每个结点为根结点的子树结点总数(孩子节点总数+1)。
3.遍历一遍dfs序列,记下每个结点编号对应的下标,方便下面查询。
4.查询:情况1:k > 以结点u为根节点的子树结点总数,输出-1;
情况2:否则,找到该节点对应下标(上一步保存了下来),在加上k-1,就是第k个dfs到的结点编号。

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

using namespace std;

const int N = 200010;

int n, m;
vector<int> g[N];
int q[N], p[N], top;//q[N]用来存dfs中第几个点,p[N]用来存点的下标,top用来表示当前遍历到的点
int sz[N];//用来存每颗子树的大小

void dfs(int u)
{
    sz[u] = 1;
    q[top] = u, p[u] = top;
    top ++ ;

    for (auto v: g[u])
    {
        dfs(v);
        sz[u] += sz[v];
    }
}

int main()
{
    scanf("%d%d", &n, &m);

    for (int i = 2; i <= n; i ++ )
    {
        int t;
        scanf("%d", &t);//读入父节点
        g[t].push_back(i);//父节点的i个儿子
    }

    dfs(1);

    while (m -- )
    {
        int u, k;
        scanf("%d%d", &u, &k);
        if (k > sz[u]) puts("-1");
        else printf("%d\n", q[p[u] + k - 1]);//因为求得是从p[u]开始往后数k个包括p[u],所以就是第p[u]+k-1个
    }

    return 0;
}

还是自己太菜,刷题太少,希望以后别再爆0,加油

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值