GPLT-L2-题解

注意: \color{red}{注意:} 注意: 个人博客传送门

L2-001 紧急救援

思路:

  • 首先,看到这个 n n n 的范围,我们要想到哪几种算法可以通过
  • 朴素版 d i j k s t r a dijkstra dijkstra F l o y d Floyd Floyd 都可以通过,但本题使用 F l o y d Floyd Floyd 不好处理,所以我们选用 d i j s t r a dijstra dijstra
  • 然后我们跑一遍 d i j k s t r a dijkstra dijkstra ,将所有到 S S S 的最短距离求出来
  • 然后我们 d f s dfs dfs 一遍,只要走到了 D D D 点,就个数加 1 1 1​,同时更新最大的人数和路径

时间复杂度: O ( n 2 ) O(n^2) O(n2)

#include <bits/stdc++.h> 

using i64 = long long;

constexpr int inf = 0x3f3f3f3f;

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M, S, D;
    std::cin >> N >> M >> S >> D;

    std::vector<int> a(N + 1);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i];
    }

    std::vector d(N + 1, std::vector<int>(N + 1));
    for (int i = 0; i <= N; i++) {
        for (int j = 0; j <= N; j++) {
            if (i == j) {
                d[i][j] = 0;
            } else {
                d[i][j] = inf;
            }
        }
    }
    for (int i = 0; i < M; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;

        d[u][v] = w; d[v][u] = w;
    }

    std::vector<int> dist(N + 1), vis(N + 1);
    auto dijkstra = [&]() {
        for (int i = 0; i < N; i++) {
            dist[i] = d[S][i];
        }
        for (int i = 0; i < N; i++) {
            int min = inf;
            int t = -1;
            for (int j = 0; j < N; j++) {
                if (!vis[j] && (t == -1 || dist[t] > dist[j])) {
                    min = dist[j];
                    t = j;
                }
            }
            for (int j = 0; j < N; j++) {
                dist[j] = std::min(dist[j], dist[t] + d[t][j]);
            }
            vis[t] = true;
        }
    };
    dijkstra();
    
    int max = 0, cnt = 0;
    vis.assign(N + 1, 0);

    std::vector<int> path, ans;
    path.push_back(S);

    auto dfs = [&](auto self, int u, int v) -> void {
        if (u == D) {
            if (v > max) {
                max = v;
                ans = path;
            }
            cnt++;
            return ;
        }
        for (int i = 0; i < N; i++) {
            if (d[u][i] && !vis[i] && dist[i] == dist[u] + d[u][i]) { // 如果 S 到 i 的距离 == S 到 当前这个点的距离 + 当前这个点到 i 的距离
                vis[i] = true;
                path.push_back(i);
                self(self, i, v + a[i]);
                path.pop_back();
                vis[i] = false;
            }
        }
    };
    dfs(dfs, S, a[S]);
    
    std::cout << cnt << " " << max << "\n";
    for (int i = 0; i < ans.size(); i++) {
        std::cout << ans[i] << " \n"[i == ans.size() - 1];
    }

    return 0;
}

L2-002 链表去重

思路:

  • bfs把这个完整的链表建出来,然后我们去重进行重置前后的地址即可

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::string st;
    std::cin >> st >> N;

    std::map<std::string, std::pair<int, std::string>> mp; 
    for (int i = 0; i < N; i++) {
        int w;
        std::string x, y;
        std::cin >> x >> w >> y;
        mp[x] = {w, y};
    }

    std::vector<std::tuple<std::string, int, std::string>> a;
    std::queue<std::string> q;
    q.push(st);
    while (q.size()) {
        auto cur = q.front();
        q.pop();

        if (mp.count(cur)) {
            a.push_back({cur, mp[cur].first, mp[cur].second});
            q.push(mp[cur].second);
        }
    }

    std::map<int, int> cnt;
    std::vector<int> vis(a.size());
    for (int i = 0; i < a.size(); i++) {
        auto [x, y, z] = a[i];
        if (cnt[abs(y)]) {
            continue ;
        }
        cnt[abs(y)]++;
        vis[i] = true;
    }

    std::vector<std::tuple<std::string, int, std::string>> b;
    for (int i = 0; i < a.size(); i++) {
        if (vis[i]) {
            b.push_back(a[i]);
        }
    }

    for (int i = 0; i < b.size(); i++) {
        if (i + 1 < b.size()) {
            auto &[x1, y1, z1] = b[i];
            auto &[x2, y2, z2] = b[i + 1];
            if (z1 != x2) {
                z1 = x2;
            }
        } else {
            auto &[x1, y1, z1] = b[i];
            z1 = "-1";
        }
    }
    for (int i = 0; i < b.size(); i++) {
        auto [x, y, z] = b[i];
        std::cout << x << " " << y << " " << z << "\n";
    }
    b.clear();
    for (int i = 0; i < a.size(); i++) {
        if (!vis[i]) {
            b.push_back(a[i]);
        }
    }
    for (int i = 0; i < b.size(); i++) {
        if (i + 1 < b.size()) {
            auto &[x1, y1, z1] = b[i];
            auto &[x2, y2, z2] = b[i + 1];
            if (z1 != x2) {
                z1 = x2;
            }
        } else {
            auto &[x1, y1, z1] = b[i];
            z1 = "-1";
        }
    }
    for (int i = 0; i < b.size(); i++) {
        auto [x, y, z] = b[i];
        std::cout << x << " " << y << " " << z << "\n";
    }
    return 0;
}

L2-003 月饼

思路:

  • 贪心,我们存一下每个月饼的收益,然后从大到小排序即可
  • 然后逐个选取

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(2);

    int N, D;
    std::cin >> N >> D;

    std::vector<double> a(N), w(N);
    for (int i = 0; i < N; i++) {
    	std::cin >> a[i];
    }
    std::vector<double> rate(N);
    for (int i = 0; i < N; i++) {
    	std::cin >> w[i];
    	rate[i] = w[i] * 1.0 / a[i];
    }

    std::vector<int> p(N);
    std::iota(p.begin(), p.end(), 0);

    std::sort(p.begin(), p.end(), 
    	[&](int i, int j) {
    		if (rate[i] == rate[j]) return a[i] > a[j];
            return rate[i] > rate[j];
    });

    double ans = 0;
    for (int i = 0; i < N; i++) {
    	if (a[p[i]] <= D) {
    		D -= a[p[i]];
    		ans += w[p[i]];
    	} else {
    		ans += D * 1.0 * w[p[i]] / a[p[i]];
    		break;
    	}
    }
    std::cout << ans << "\n";
    
    return 0;
}

L2-004 这是二叉搜索树吗?

思路:

  • 首先我们假设这个树是非镜面二叉搜索树,一开始设okfalse,然后我们将其从先序转换为后序,假如发现这个转换后的后序数组长度不为n,那么就清空,将他按照镜面二叉搜索树的情况来求后续遍历
  • 只要以上两种情况中的任何一种合法,就直接输出,否则输出-1

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    std::vector<int> pre(n);
    for (int i = 0; i < n; i++) {
        std::cin >> pre[i];
    }

    bool ok = false;
    std::vector<int> post;
    auto get = [&](auto self, int root, int tail) -> void {
        if (root > tail) return ;
        int i = root + 1, j = tail;
        if (!ok) {
            while (i <= tail && pre[root] > pre[i]) i++;
            while (j > root && pre[root] <= pre[j]) j--;
        } else {
            while (i <= tail && pre[root] <= pre[i]) i++;
            while (j > root && pre[root] > pre[j]) j--;
        }
        if (i - j != 1) return ;
        self(self, root + 1, j);
        self(self, i, tail);
        post.push_back(pre[root]);
    };

    get(get, 0, n - 1);
    if (post.size() != n) {
        ok = true;
        post.clear();
        get(get, 0, n - 1);
    }
    if (post.size() == n) {
        std::cout << "YES\n";
        for (int i = 0; i < post.size(); i++) {
            std::cout << post[i] << " \n"[i == post.size() - 1];
        }
    } else {
        std::cout << "NO\n";
    }
    
    return 0;
}

L2-005 集合相似度

题目大意:

  • 其中 N c N_c Nc 是两个集合都有的不相等整数的个数:两个集合交集元素个数

  • N t N_t Nt 是两个集合一共有的不相等整数的个数:两个集合的并集的元素个数

思路:

  • set直接进行集合去重和统计个数

时间复杂度: O ( K l o g M ) O(KlogM) O(KlogM)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<std::vector<int>> st(N);
    for (int i = 0; i < N; i++) {
        int n;
        std::cin >> n;
        std::set<int> a;
        for (int j = 0; j < n; j++) {
            int x;
            std::cin >> x;
            a.insert(x);
        }
        for (auto x : a) {
            st[i].push_back(x);
        }
    }

    int K;
    std::cin >> K;

    while (K--) {
        int a, b;
        std::cin >> a >> b;
        a--, b--;

        std::set<int> k;
        for (auto v : st[a]) {
            k.insert(v);
        }
        int ans = 0;
        for (auto v : st[b]) {
            if (k.count(v)) {
                ans++;
            }
        }
        for (auto v : st[b]) {
            k.insert(v);
        }
        printf("%.2lf%\n", ans * 100.0 / k.size());
    }

    return 0;
}

L2-006 树的遍历

思路:

  • 根据中序遍历和后序遍历建树,然后进行BFS即可

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    std::vector<int> post(n), in(n);
    for (int i = 0; i < n; i++) {
    	std::cin >> post[i];
    }

    std::unordered_map<int, int> pos, l, r;
    auto build = [&](auto self, int il, int ir, int pl, int pr) -> int {
    	int root = post[pr]; // 后序遍历的最后一个节点即为根节点
        int k = pos[root]; // 在中序遍历中找到根节点的位置
        // k - il 为左子树的节点个数  
    	if (il < k) l[root] = self(self, il, k - 1, pl, pl + k - 1 - il);
    	if (ir > k) r[root] = self(self, k + 1, ir, pl + k - 1 - il + 1, pr - 1);
    	return root;
    };
    for (int i = 0; i < n; i++) {
    	std::cin >> in[i];
    	pos[in[i]] = i; // 记录中序遍历中节点值与索引的映射关系
    }
    int root = build(build, 0, n - 1, 0, n - 1);

    std::queue<int> q;
    q.push(root);

    std::vector<int> ans;
    while (!q.empty()) {
    	int t = q.front();
    	q.pop();

    	ans.push_back(t);
    	if (l.count(t)) q.push(l[t]);
    	if (r.count(t)) q.push(r[t]);
    }
    
    for (int i = 0; i < ans.size(); i++) {
    	std::cout << ans[i] << " \n"[i == ans.size() - 1];
    }

    return 0;
}

L2-007 家庭房产

思路:

  • 将每一个家庭看作一个集合,然后用并查集来维护每一个家庭
  • 在合并的过程中,由于题目要求输出家庭里最小的那个编号,那么这个最小的编号就作为祖先节点
  • 然后我们遍历,求出每个家庭的信息,最后统计输出即可

时间复杂度: O ( n ) O(n) O(n)

struct DSU {
    std::vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        if (x > y) { // 保证小的那个是祖先
            f[x] = y;
        } else {
            f[y] = x;
        }
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

struct node1 {
    int id, fa, mo;
    int cnt, area;
    int c[5];
};

struct node2 {
    int id, peo;
    double num, area;
    bool ok = false;
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;  

    DSU f(10010);

    std::vector<node1> a(N);
    std::vector<int> vis(10010);
    for (int i = 0; i < N; i++) {
        int k;
        std::cin >> a[i].id >> a[i].fa >> a[i].mo >> k;
        vis[a[i].id] = true;
        if (a[i].fa != -1) {
            vis[a[i].fa] = true;
            f.merge(a[i].fa, a[i].id);
        }
        if (a[i].mo != -1) {
            vis[a[i].mo] = true;
            f.merge(a[i].mo, a[i].id);
        }
        for (int j = 0; j < k; j++) {
            std::cin >> a[i].c[j];
            vis[a[i].c[j]] = true;
            f.merge(a[i].c[j], a[i].id);
        }
        std::cin >> a[i].cnt >> a[i].area;
    }
    
    std::vector<node2> ans(10000);
    for (int i = 0; i < N; i++) {
        int pa = f.find(a[i].id);
        ans[pa].id = pa;
        ans[pa].num += a[i].cnt;
        ans[pa].area += a[i].area;
        ans[pa].ok = true;
    }
    int cnt = 0;
    for (int i = 0; i < 10000; i++) {
        if (vis[i]) {
            ans[f.find(i)].peo++;
        }
        if (ans[i].ok) {
            cnt++;
        }
    }
    for (int i = 0; i < 10000; i++) {
        if (ans[i].ok) {
            ans[i].num = (ans[i].num * 1.0 / ans[i].peo);
            ans[i].area = (ans[i].area * 1.0 / ans[i].peo);
        }
    }
    
    std::sort(ans.begin(), ans.end(), [&](auto i, auto j) {
        if (i.area != j.area) {
            return i.area > j.area;
        }
        return i.id < j.id;
    });
    printf("%d\n", cnt);
    for (int i = 0; i < cnt; i++) {
        printf("%04d %d %.3f %.3f\n", ans[i].id, ans[i].peo, ans[i].num, ans[i].area);
    }

    return 0;
}

L2-008 最长对称子串

思路:

  • 用字符串 h a s h hash hash 来判断回文串,然后枚举左右端点即可

本题也可以参考一下升级版智乃的前缀、后缀、回文的讲解

时间复杂度: O ( n 2 ) O(n^2) O(n2)

struct Shash{
    const i64 base[2] = {29, 31};
    const i64 hashmod[2] = {(i64)1e9, 998244353};

    std::array<std::vector<i64>, 2> hsh, pwMod;
    void init(std::string &s) {
        int n = s.size(); 
        s = ' ' + s;
        hsh[0].resize(n + 1), hsh[1].resize(n + 1);
        pwMod[0].resize(n + 1), pwMod[1].resize(n + 1);
        for(int i = 0; i < 2; i++){
            pwMod[i][0] = 1;
            for(int j = 1; j <= n; j++){
                pwMod[i][j] = pwMod[i][j - 1] * base[i] % hashmod[i];
                hsh[i][j] = (hsh[i][j - 1] * base[i] + s[j]) % hashmod[i];
            }
        }
    }
    std::pair<i64, i64> get(int l, int r) {
        std::pair<i64, i64> ans;
        ans.first = (hsh[0][r] - hsh[0][l - 1] * pwMod[0][r - l + 1]) % hashmod[0];
        ans.second = (hsh[1][r] - hsh[1][l - 1] * pwMod[1][r - l + 1]) % hashmod[1];
        ans.first = (ans.first + hashmod[0]) % hashmod[0];
        ans.second = (ans.second + hashmod[1]) % hashmod[1];
        return ans;
    }
    bool same(int la, int ra, int lb, int rb){
        return get(la, ra) == get(lb, rb);
    }
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::string s;
    std::getline(std::cin, s);

    for (auto &i : s) {
        if (i == ' ') {
            i = 'a';
        }
    }

    std::string t = std::string(s.rbegin(), s.rend());

    Shash a, b;
    a.init(s); b.init(t);

    int n = s.size();   

    int ans = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            if (a.get(i, j) == b.get(n - j, n - i)) {
                ans = std::max(ans, j - i + 1);
            }
        }
    }
    std::cout << ans << "\n";

    
    return 0;
}

L2-009 抢红包

思路:

  • 直接模拟就行

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(2);

    int N;
    std::cin >> N;

    std::vector<std::tuple<double, int, int>> a(N + 1);
    for (int i = 0; i < N; i++) {
        auto &[x, y, z] = a[i + 1];
        y = i + 1;
    	int k;
    	std::cin >> k;
    	double sum = 0;
    	for (int j = 0; j < k; j++) {
    		int id;
    		double m;
    		std::cin >> id >> m;
            auto &[x1, y1, z1] = a[id];
    		x1 += m;
    		y1 = id;
            z1++;
    		sum += m;
    	}
    	x -= sum;
    }
    std::sort(a.begin() + 1, a.end(), [&](auto i, auto j) {
        auto [x1, y1, z1] = i;
        auto [x2, y2, z2] = j;
    	if (x1 == x2) {
            if (z1 != z2) {
                return z1 > z2;
            } else {
                return y1 < y2;
            }
        }
        return x1 > x2;
    	
    });
    for (int i = 1; i <= N; i++) {
        auto [x, y, z] = a[i];
    	std::cout << y << " " << x / 100 << "\n";
    }
    
    return 0;
}

L2-010 排座位

思路:

  • 用并查集维护一下朋友关系
  • 然后用 set 维护一下敌对关系

时间复杂度: O ( M l o g N ) O(MlogN) O(MlogN)

struct DSU {
    std::vector<int> f, siz;

    DSU() {}
    DSU(int n) {
        init(n);
    }

    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 0);
    }

    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M, K;
    std::cin >> N >> M >> K;

    DSU f(N + 1);

    std::set<std::pair<int, int>> em;
    for (int i = 0; i < M; i++) {
        int x, y, op;
        std::cin >> x >> y >> op;

        if (op == -1) {
            em.insert({x, y});
            em.insert({y, x});
        } else {
            f.merge(x, y);
        }
    }

    for (int i = 0; i < K; i++) {
        int x, y;
        std::cin >> x >> y;

        if (!f.same(x, y) && !em.count({x, y})) {
            std::cout << "OK\n";
        } else if (f.same(x, y) && em.count({x, y})) {
            std::cout << "OK but...\n";
        } else if (em.count({x, y})) {
            std::cout << "No way\n";
        } else if (f.same(x, y)) {
            std::cout << "No problem\n";
        }
    }

    return 0;
}

L2-011 玩转二叉树

思路:

  • 按照规则构建一颗二叉树
  • 然后 bfs 的时候,将左右节点的输出顺序更换一下即可

时间复杂度: O ( n ) O(n) O(n)

struct Node {
	int val;
	Node *l;
	Node *r;
	Node(int x) : val(x), l(nullptr), r(nullptr) {}
};

class Solution {
public:
	Node* build(std::vector<int> &ino, std::vector<int> &pre) {
		std::unordered_map<int, int> mp;
		for (int i = 0; i < ino.size(); i++) {
			mp[ino[i]] = i;
		}
		return buildTree(ino, 0, ino.size() - 1, pre, 0, pre.size() - 1, mp);
	}
	Node* buildTree(auto &ino, int il, int ir, auto &pre, int pl, int pr, auto mp) {
		if (pl > pr) {
			return nullptr;
		}
		int root_val = pre[pl];
		Node *root = new Node(root_val);

		int tot = mp[root_val]; // 根节点的位置
		int ls = tot - il; // 左子树的大小

		root->l = buildTree(ino, il, tot - 1, pre, pl + 1, pl + ls, mp);
		root->r = buildTree(ino, tot + 1, ir, pre, pl + ls + 1, pr, mp);
		return root;
	}
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    std::vector<int> ino(n), pre(n);
    for (int i = 0; i < n; i++) {
    	std::cin >> ino[i];
    }
    for (int i = 0; i < n; i++) {
    	std::cin >> pre[i];
    }

  	Solution s;
    Node* root = s.build(ino, pre);
    
    std::queue<Node*> q;
    q.push(root);

    std::vector<int> ans;
    while (!q.empty()) {
    	auto t = q.front();
    	q.pop();

    	ans.push_back(t->val);
    	if (t->r != nullptr) q.push(t->r);
    	if (t->l != nullptr) q.push(t->l);
    }
    for (int i = 0; i < ans.size(); i++) {
    	std::cout << ans[i] << " \n"[i == ans.size() - 1];
    }

    return 0;
}

L2-013 红色警报

思路:

  • 统计这个图的连通分量,然后每次摧毁一个城市,在求一次连通分量;
  • 如果摧毁后的连通分量大于摧毁前的连通分量数+1,那么,就说明,这个节点导致了这个图不连通了,那么我们就需要输出Red Alert: City k is lost!,否则输出City k is lost.
  • 如果K的数量等于N,那么就说明最后就摧毁完了,输出Game Over.

时间复杂度: O ( K × n 2 ) O(K \times n^2) O(K×n2)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N, M;
    std::cin >> N >> M;

    std::vector<std::vector<int>> g(N, std::vector<int>(N));
    for (int i = 0; i < M; i++) {
    	int u, v;
    	std::cin >> u >> v;
    	g[u][v] = g[v][u] = 1;
    }

    std::vector<int> vis(N);
    auto dfs = [&](auto self, int u) -> void {
    	vis[u] = true;
    	for (int i = 0; i < N; i++) {
    		if (g[u][i] && !vis[i]) {
    			self(self, i);
    		}
    	}
    };
    auto count = [&]() {
    	int cnt = 0;
    	vis.assign(N, 0);
    	for (int i = 0; i < N; i++) {
    		if (!vis[i]) {
    			dfs(dfs, i);
    			cnt++;
    		}
    	}
    	return cnt;
    };
    int cnt = count();

    int K;
    std::cin >> K;

    for (int i = 0; i < K; i++) {
    	int x;
    	std::cin >> x;

    	for (int j = 0; j < N; j++) {
    		if (g[x][j]) {
    			g[x][j] = 0;
    			g[j][x] = 0;
    		}
    	}
    	int t = count();
    	if (t > cnt + 1) {
    		std::cout << "Red Alert: City " << x << " is lost!\n";
    	} else {
    		std::cout << "City " << x << " is lost.\n";
    	}
    	cnt = t;
    	if (i == N - 1) {
    		std::cout << "Game Over.\n";
    	}
    }

    return 0;
}

L2-014 列车调度

思路:

  • 每次将队列的第i个数与目前的最大值进行比较,只要出现一个比当前值小的数,我们就把比这个数大的数删掉,这样保证是从大到小的顺序,最后只需要输出这个有序队列的剩下元素的大小-1即可

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N;
    std::cin >> N;

    std::set<int> st;
    st.insert(0);
    for (int i = 0; i < N; i++) {
        int x;
        std::cin >> x;

        if (x < *st.rbegin()) {
            st.erase(*st.upper_bound(x));
        }
        st.insert(x);
    }

    std::cout << st.size() - 1 << "\n";

    return 0;
}

L2-015 互评成绩

思路:

  • 按照规则模拟

时间复杂度: O ( n k ) O(nk) O(nk)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(3);

    int N, k, M;
    std::cin >> N >> k >> M;

    std::vector<double> score;
    for (int i = 0; i < N; i++) {
    	std::vector<double> a(k);
    	for (int j = 0; j < k; j++) {
    		std::cin >> a[j];
    	}
    	std::sort(a.begin(), a.end());
    	double avg = std::accumulate(a.begin() + 1, a.end() - 1, 0.0) / (k - 2);
    	score.push_back(avg);
    }

    std::sort(score.begin(), score.end());
    for (int i = N - M; i < N; i++) {
    	std::cout << score[i] << " \n"[i == N - 1];
    }
    
    return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹

思路:

  • 暴搜,统计 xy 相差的代数

时间复杂度: O ( n + k D ) O(n + kD) O(n+kD)

struct node {
    char sex = '\0';
    int faid = -1, moid = -1;
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;
    
    std::vector<node> a(100000);
    for (int i = 0; i < N; i++) {
        int id;
        std::cin >> id;
        std::cin >> a[id].sex >> a[id].faid >> a[id].moid;
        if (a[id].faid != -1)
            a[a[id].faid].sex = 'M';
        if (a[id].moid != -1)
            a[a[id].moid].sex = 'F';
    }
    
    auto dfs = [&](auto self, int x, int y, int d) -> bool {
        if (!(x != -1 && y != -1)) {
            return true;
        }
        if (d > 5) return true;
        
        if (x == y) { 
            return false;
        } else {
            return self(self, a[x].faid, a[y].moid, d + 1) && self(self, a[x].faid, a[y].faid, d + 1)
            && self(self, a[x].moid, a[y].moid, d + 1) && self(self, a[x].moid, a[y].faid, d + 1);
        }
    };
    
    int K;
    std::cin >> K;

    while (K--) {
        int x, y;
        std::cin >> x >> y;

        if (a[x].sex == a[y].sex) {
            std::cout << "Never Mind\n";
        } else {
            if (dfs(dfs, x, y, 1)) {
                std::cout << "Yes\n";
            } else {
                std::cout << "No\n";
            }
        }
    }

    return 0;
}

L2-017 人以群分

思路:

  • 模拟即可

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> a(N);
    for (int i = 0; i < N; i++) {
    	std::cin >> a[i];
    }
    std::sort(a.begin(), a.end());

    int mid = N / 2;
    i64 sum1 = std::accumulate(a.begin(), a.begin() + mid, 0LL);
    i64 sum2 = std::accumulate(a.begin() + mid, a.end(), 0LL);
   
    printf("Outgoing #: %d\n", (N + 1) / 2);
    printf("Introverted #: %d\n", N / 2);
    printf("Diff = %lld\n", sum2 - sum1);
    
    return 0;
}

L2-019 悄悄关注

思路:

  • 直接模拟,判断在不在那个关注集合就行

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::set<std::string> st;
    for (int i = 0; i < N; i++) {
    	std::string s;
    	std::cin >> s;
    	st.insert(s);
    }

    int M;
    std::cin >> M;

    double sum = 0;
    std::vector<std::pair<std::string, int>> a(M);
    for (int i = 0; i < M; i++) {
    	std::cin >> a[i].first >> a[i].second;
    	sum += a[i].second;
    }

    sum /= M;

    std::set<std::string> ans;
    for (int i = 0; i < M; i++) {
    	if (!st.count(a[i].first) && a[i].second > sum) {
    		ans.insert(a[i].first);
    	}
    }
    if (ans.empty()) {
    	std::cout << "Bing Mei You\n";
    	return 0;
    }
    for (auto x : ans) {
    	std::cout << x << "\n";
    }
    
    return 0;
}

L2-020 功夫传人

思路:

  • 直接 BFS 或者 DFS

时间复杂度: O ( N ) O(N) O(N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    double Z, r;
    std::cin >> N >> Z >> r;

    std::map<int, i64> mp;
    std::vector<std::vector<int>> g(N);
    for (int i = 0; i < N; i++) {
    	int k;
    	std::cin >> k;

    	if (k == 0) {
    		i64 x;
    		std::cin >> x;
    		mp[i] = x;
    	}
    	for (int j = 0; j < k; j++) {
			int x;
			std::cin >> x;
			g[i].push_back(x);
		}
    }

    if (mp.count(0)) {
    	std::cout << i64(Z * mp[0]) << "\n";
    	return 0;
    }
    std::queue<std::tuple<int, double>> q;
    q.push({0, Z});


    double ans = 0;
    while (q.size()) {	
    	auto [x, y] = q.front();
    	q.pop();

    	for (int v : g[x]) {
    		if (mp.count(v)) {
    			double t = mp[v] * y * (1 - r / 100);
    			q.push({v, t});
    			ans += t;
    		} else {
    			q.push({v, y * (1 - r / 100)});
    		}
    	}
    }
    std::cout << i64(ans) << "\n";

    return 0;
}

L2-021 点赞狂魔

思路:

  • 可以利用优先队列来存储答案,利用 mapset 来去重,然后按规则模拟即可

时间复杂度: O ( n l o g l o g n ) O(nloglogn) O(nloglogn)

struct node {
    std::string s;
    int x;
    double avg;

    bool operator<(const node &t) const {
        if (x == t.x) {
            return avg > t.avg;
        }
        return x < t.x;
    }
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;
    std::map<std::string, double> avg;
    std::map<std::string, std::set<int>> mp;
    for (int i = 0; i < N; i++) {
        int K;
        std::string s;
        std::cin >> s >> K;
        for (int j = 0; j < K; j++) {
            int x;
            std::cin >> x;
            mp[s].insert(x);
        }
        avg[s] = K * 1.0 / int(mp[s].size());
    }

    std::priority_queue<node> q;
    for (auto [s, y] : mp) {
        q.push({s, y.size(), avg[s]});
    }   
    int cnt = 0;
    while (!q.empty()) {
        cnt++;
        if (cnt == 3) {
            std::cout << q.top().s;
            break;
        }
        std::cout << q.top().s << " ";
        q.pop();
    }
    if (cnt < 3) {
        for (int i = cnt; i < 3; i++) {
            std::cout << '-' << " \n"[i == 2];
        }
    }

    return 0;
}

L2-023 图着色问题

思路:

  • 数据范围较小,其实可以直接暴力枚举,然后 check 一下当前位置是否可行,不过我这里用了 BFS 来模拟这个 check 的过程
  • 如果个数不是 K 直接判定为 No

时间复杂度: O ( V × N ) O(V \times N) O(V×N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int V, E, K;
    std::cin >> V >> E >> K;

    std::vector<std::vector<int>> adj(V);
    for (int i = 0; i < E; i++) {
        int u, v;
        std::cin >> u >> v;
        u--, v--;

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    int N;
    std::cin >> N;

    while (N--) {
        std::set<int> st;
        std::vector<int> c(V);
        for (int i = 0; i < V; i++) {
            std::cin >> c[i];
            st.insert(c[i]);
        }

        std::vector<int> vis(V);
        auto bfs = [&](int u) -> bool {
            std::queue<int> q;
            vis[u] = true;
            q.push(u);

            while (!q.empty()) {
                int x = q.front();
                q.pop();

                for (int v : adj[x]) {
                    if (c[v] == c[x]) return false;
                    if (vis[v]) continue ;
                    vis[v] = true;
                    q.push(v);
                }
            }
            return true;
        };
        if (st.size() == K && bfs(0) && bfs(V - 1)) {
            std::cout << "Yes\n";
        } else {
            std::cout << "No\n";
        }
    }
    
    return 0;
}

L2-024 部落

思路:

  • 并查集,查询集合即可

时间复杂度: O ( N × K ) O(N \times K) O(N×K)

struct DSU {
    std::vector<int> f, siz;

    DSU() {}
    DSU(int n) {
        init(n);
    }

    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }

    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += y;
        f[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }
};


signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    DSU f(10010);


    std::vector<int> vis(10010);
    for (int i = 0; i < N; i++) {
        int k, v;
        std::cin >> k >> v;
        vis[v] = true;
        int pa = f.find(v);
        for (int j = 1; j < k; j++) {
            int x;
            std::cin >> x;

            vis[x] = true;
            f.merge(x, pa);
        }
    }

    int cnt = 0;
    std::set<int> st;
    for (int i = 1; i <= 10000; i++) {
        if (!vis[i]) continue ;
        else {
            cnt++;
            st.insert(f.find(i));
        }
    }

    std::cout << cnt << " " << st.size() << "\n";

    int Q;
    std::cin >> Q;

    while (Q--) {
        int x, y;
        std::cin >> x >> y;

        if (f.same(x, y)) {
            std::cout << "Y\n";
        } else {
            std::cout << "N\n";
        }
    }

    return 0;
}

L2-025 分而治之

思路:

  • 直接记录每个点的度(deg)情况即可,然后每当删除一个点就把与这些点相连的点的度数都减 1,最后判断是否其他的点的度数为 0 即可,这样保证了度数为 0 的点是孤立的

时间复杂度: O ( Q × N l o g N ) O(Q \times NlogN) O(Q×NlogN)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M;
    std::cin >> N >> M;

    std::vector<int> deg(N);
    std::vector<std::vector<int>> adj(N);
    for (int i = 0; i < M; i++) {
    	int u, v;
    	std::cin >> u >> v;
    	u--, v--;

    	adj[u].push_back(v);
    	adj[v].push_back(u);
    	deg[u]++, deg[v]++;
    }

    int Q;
    std::cin >> Q;

    while (Q--) {
    	int Np;
    	std::cin >> Np;

    	auto tmp = deg;
    	std::set<int> a;
    	for (int i = 0; i < Np; i++) {
    		int x;
    		std::cin >> x;
    		x--;
    		a.insert(x);

    		for (int v : adj[x]) {
    			tmp[v]--;
    		}
    	}
    	bool ok = false;
    	for (int i = 0; i < N; i++) {
    		if (a.count(i)) continue ;
    		if (tmp[i] != 0) {
    			ok = true;
    			break;
    		}
    	}
    	std::cout << (ok ? "NO\n": "YES\n");
    }
    
    return 0;
}

L2-026 小字辈

思路:

  • 两遍 dfs,第一遍先记录族谱树的最大深度,第二遍找到最大深度的所有节点,即为辈分最小的节点

时间复杂度: O ( N ) O(N) O(N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> a(N + 1);
    for (int i = 1; i <= N; i++) {
        std::cin >> a[i];
    }

    int u = 0;
    std::map<int, std::vector<int>> mp;
    for (int i = 1; i <= N; i++) {
        mp[a[i]].push_back(i);
        if (a[i] == -1) {
            u = i;
        }
    }

    int cnt = 0;
    auto dfs1 = [&](auto self, int x, int dep) -> void {
        cnt = std::max(cnt, dep);
        for (int v : mp[x]) {
            self(self, v, dep + 1);
        }
    };  
    dfs1(dfs1, u, 1);
    
    std::vector<int> ans;
    auto dfs2 = [&](auto self, int x, int dep) -> void {
        if (dep == cnt) {
            ans.push_back(x);
            return ;
        }
        for (int v : mp[x]) {
            self(self, v, dep + 1);
        }
    };  

    dfs2(dfs2, u, 1);

    std::cout << cnt << "\n";
    for (int i = 0; i < ans.size(); i++) {
        std::cout << ans[i] << " \n"[i == ans.size() - 1];
    }

    return 0;
}

L2-027 名人堂与代金券

思路:

  • 直接模拟即可,利用 mapset 处理所有的顺序

时间复杂度: O ( k l o g l o g n ) O(kloglogn) O(kloglogn)

struct node {
    std::string s;
    int w;
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, G, K;
    std::cin >> N >> G >> K;

    std::vector<node> a(N);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i].s >> a[i].w;
    }

    int ans = 0;
    for (int i = 0; i < N; i++) {
        if (a[i].w >= 60 && a[i].w < G) {
            ans += 20;
        } else if (a[i].w >= G && a[i].w <= 100) {
            ans += 50;
        }
    }

    std::map<int, std::set<std::string>, std::greater<int>> mp;
    for (auto [x, y] : a) {
        mp[y].insert(x);
    }

    std::cout << ans << "\n";
    int tot = 0, lst = 0;
    std::vector<std::pair<std::string, int>> res;
    for (auto [x, y] : mp) {
        tot += 1;
        for (auto s : y) {
            std::cout << tot + lst << " " << s << " " << x << "\n";
        }
        lst += y.size() - 1;
        if (lst + tot >= K) break;
    }

    return 0;
}

L2-029 特立独行的幸福

思路:

  • 模拟,用 set 记录一下是否依赖即可,然后记录幸福数的个数

时间复杂度: O ( n l o g x ) O(nlogx) O(nlogx)

bool isprime(int x) {
	if (x <= 1) return false;
	for (int i = 2; i <= x / i; i++) {
		if (x % i == 0) return false;
	}
	return true;
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int A, B;
    std::cin >> A >> B;

    std::vector<int> cnt(100010), vis(100010);
    auto check = [&](int x) {
        std::set<int> st;
        int t = x;
        while (t != 1) {
            st.insert(t);
            int sum = 0;
            while (t) {
                int v = t % 10;
                t /= 10;
                sum += v * v;
            }
            cnt[x]++;
            vis[sum] = 1;
            t = sum;
            if (st.count(t)) return false;
        }
        return true;
    };

    std::vector<int> ans;
    for (int i = A; i <= B; i++) {
        if (check(i)) ans.push_back(i);	
    }
    bool ok = false;
    for (int i = 0; i < ans.size(); i++) {
        if (isprime(ans[i])) cnt[ans[i]] <<= 1;
        if (!vis[ans[i]]) {
            std::cout << ans[i] << " " << cnt[ans[i]] << "\n";
            ok = true;
        }
    }
    if (!ok) {
        std::cout << "SAD\n";
    }

    return 0;
}

L2-030 冰岛人

思路:

  • 利用 map 来存储维京男性和维京女性以及普通男性和普通女性的姓名
  • 然后利用暴力搜索出五代以内是否有公共祖先

时间复杂度: O ( N × l o g N ) O(N \times logN) O(N×logN)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::map<std::string, std::pair<int, std::string>> Record;
    for (int i = 0; i < N; i++) {
    	std::string fname, sname;
    	std::cin >> fname >> sname;
    	if (sname.back() == 'n') { // 维京男性
    		Record[fname] = {1, sname.substr(0, sname.size() - 4)};
    	} else if (sname.back() == 'r') { // 维京女性
    		Record[fname] = {0, sname.substr(0, sname.size() - 7)};	
    	} else if (sname.back() == 'm') { // 普通男性
    		Record[fname].first = 1;
    	} else { // 普通女性
    		Record[fname].first = 0;
    	}
    }

    auto check = [&](std::string a, std::string b) {
    	int cnt1 = 0, cnt2;
	    while (a != "") {
	        cnt2 = 0;
	        std::string b2 = b;
	        while (b2 != "") {
	            if (a == b2 && (cnt1 < 4 || cnt2 < 4)) return "No\n";
	            if (cnt1 >= 4 && cnt2 >= 4) return "Yes\n";
	            b2 = Record[b2].second;
	            cnt2++;
	        }
	        a = Record[a].second;
	        cnt1++;
	    }
	    return "Yes\n";
    };

    int M;
    std::cin >> M;

    while (M--) {
    	std::string fname, temp, sname;
    	std::cin >> fname >> temp >> sname >> temp;
    	if (!Record.count(fname) || !Record.count(sname)) {
    		std::cout << "NA\n";
    	} else if (Record[fname].first == Record[sname].first) {
    		std::cout << "Whatever\n";
    	} else {
    		std::cout << check(fname, sname);
    	}
    }
    
    return 0;
}

L2-031 深入虎穴

思路:

  • 首先找到那个唯一入口门的位置,然后进行 dfs 即可,可以类比一下L2-026 小字辈这题,几乎一模一样,唯一的区别就是有向树找根,有向树的根的入度为 0.

时间复杂度: O ( N ) O(N) O(N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> deg(N);
    std::vector<std::vector<int>> adj(N);
    for (int i = 0; i < N; i++) {
    	int K;
    	std::cin >> K;

    	for (int j = 0; j < K; j++) {
    		int x;
    		std::cin >> x;
    		x--;
    		adj[i].push_back(x);
    		deg[x]++;
    	}
    }

    int u = -1;
    for (int i = 0; i < N; i++) {
    	if (!deg[i]) u = i;
    }

    int mx = 1;
    auto dfs1 = [&](auto self, int x, int dep) -> void {
    	mx = std::max(mx, dep);
    	for (int v : adj[x]) {
    		self(self, v, dep + 1);
    	}
    };
    dfs1(dfs1, u, 1);
   	
   	auto dfs2 = [&](auto self, int x, int dep) -> void {
   		if (dep == mx) {
   			std::cout << x + 1 << "\n";
   			return ;
   		}
   		for (int v : adj[x]) {
    		self(self, v, dep + 1);
    	}
   	};
    dfs2(dfs2, u, 1);

    return 0;
}

L2-032 彩虹瓶

思路:

  • 按照题目意思模拟,可以看出来就是考察的 stack 这个数据结构,只要发现存储的个数大于 M 或者无法按顺序排列,就不行

时间复杂度: O ( K N ) O(KN) O(KN)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M, K;
    std::cin >> N >> M >> K;

    for (int i = 0; i < K; i++) {
	    std::vector<int> a(N);
    	for (int j = 0; j < N; j++) {
    		std::cin >> a[j];
    	}

    	std::stack<int> stk;
    	std::vector<int> ans;
    	int tot = 1, f = 0;
    	for (int j = 0; j < N; j++) {
    		if (a[j] == tot) {
    			ans.push_back(tot);
    			tot++;
    		} else if (stk.size() && stk.top() == tot) {
    			stk.pop();
    			ans.push_back(tot);
    			tot++;
    			j--;
    		} else {
    			stk.push(a[j]);
    		}
    		if (stk.size() > M) f = true;
    	}
    	if (stk.size() > M || f) {
    		std::cout << "NO\n";
    		continue ;
    	}
    	while (stk.size()) {
    		ans.push_back(stk.top());
    		stk.pop();
    	}
    	if (std::is_sorted(ans.begin(), ans.end())) {
    		std::cout << "YES\n";
    	} else {
    		std::cout << "NO\n";
    	}
    }
    
    return 0;
}

L2-033 简单计算器

思路:

  • 利用栈按照题意模拟

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::stack<int> num;
    for (int i = 0; i < N; i++) {
        int x;
        std::cin >> x;
        num.push(x);
    }

    std::stack<char> op;
    for (int i = 0; i + 1 < N; i++) {
        char c;
        std::cin >> c;
        op.push(c);
    }
    auto check = [&](int x, int y, char op) {
        if (op == '/' && y == 0) {
            return false;
        }
        return true;
    };
    
    auto cal = [&](int x, int y, char op) {
        if (op == '/') {
            return x / y;
        }
        if (op == '*') {
            return x * y;
        }
        if (op == '-') {
            return x - y;
        }
        if (op == '+') {
            return x + y;
        }
    };

    while (num.size() > 1) {
        int y = num.top();
        num.pop();
        int x = num.top();
        num.pop();

        char c = op.top();
        op.pop();
        if (check(x, y, c)) {
            num.push(cal(x, y, c));
        } else {
            std::cout << "ERROR: " << x << "/0" << "\n";
            return 0;
        }
        if (num.size() == 1) {
            std::cout << num.top() << "\n";
            break;
        }
    }

    return 0;
}

L2-034 口罩发放

思路:

  • 首先我们创建一个结构体 node 来存储每个人的个人有关信息,然后创建一个 map 来存储最后一次的记录的日期,通过 check 函数判断是否合法,然后按照题意模拟

时间复杂度: O ( D × T l o g T ) O(D \times TlogT) O(D×TlogT)

struct node {
    std::string name, id, time;
    int ill, pos;
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int D, P;
    std::cin >> D >> P;

    std::vector<node> ill;
    std::map<std::string, int> mp;
    std::set<std::string> gotten;
    for (int t = 0; t < D; t++) {
        int T, S;
        std::cin >> T >> S;

        auto check = [&](std::string x) {
            if (x.size() != 18) return false;
            for (char c : x) {
                if (c < '0' || c > '9') return false;
            }
            return true;
        };

        std::vector<node> Record(T);
        for (int i = 0; i < T; i++) {
            std::cin >> Record[i].name >> Record[i].id >> Record[i].ill >> Record[i].time;
            Record[i].pos = i;
            if (!check(Record[i].id)) Record[i].name = "";
            else {
                if (!mp.count(Record[i].id)) mp[Record[i].id] = -30;
                if (Record[i].ill && !gotten.count(Record[i].id)) {
                    ill.push_back(Record[i]);
                    gotten.insert(Record[i].id);
                }
            }
        }
        std::sort(Record.begin(), Record.end(), [&](auto i, auto j) {
            if (i.time != j.time) return i.time < j.time;
            return i.pos < j.pos;
        });
        int sum = 0;
        for (int i = 0; i < T && sum < S; i++) {
            if (Record[i].name != "" && t - mp[Record[i].id] > P) {
                mp[Record[i].id] = t;
                sum++;
                std::cout << Record[i].name << " " << Record[i].id << "\n";
            }
        }
    }
    for (auto e : ill) {
        std::cout << e.name << " " << e.id << "\n";
    }

    return 0;
}

L2-035 完全二叉树的层序遍历

思路:

  • 可以发现,题目说这是一颗完全二叉树,那么可以知道,按照完全二叉树的遍历原理进行后序遍历,先进入左右子树(编号为index * 2index * 2 + 1,即index右移1位,和index右移1+1),cnt为后序遍历的位置标记,并将当前所在的后序遍历的元素,填入ans[index]内即可

时间复杂度: O ( N ) O(N) O(N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> a(N);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i];
    }

    int tot = 0;
    std::vector<int> ans(N + 1);
    std::function<void(int)> dfs = [&](int x) {
        if (x > N) return ;
        dfs(x << 1);
        dfs(x << 1 | 1);
        ans[x] = a[tot++];
    };

    dfs(1);
    for (int i = 1; i <= N; i++) {
        std::cout << ans[i] << " \n"[i == N];
    }

    return 0;
}

L2-037 包装机

思路:

  • 按照题目意思模拟,那个框其实就是一个栈,夹取物品就是出栈,按照意思模拟即可,只需要注意当队列为空,就不采取任何措施

时间复杂度: O ( n m ) O(nm) O(nm)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M, S;
    std::cin >> N >> M >> S;

    std::map<int, std::deque<char>> mp;
    for (int i = 0; i < N; i++) {
    	for (int j = 0; j < M; j++) {
    		char c;
    		std::cin >> c;
    		mp[i + 1].push_back(c);
    	}
    }

    int x;
    std::string ans = "";
    std::stack<char> stk;
    while (std::cin >> x && x != -1) {
    	if (x != 0) {
    		if (mp[x].empty()) continue ;
    		if (stk.size() < S) {
    			if (mp[x].size()) {
    				stk.push(mp[x].front());
    				mp[x].pop_front();
    			}
    		} else {
    			char t = stk.top();
    			stk.pop();
    			ans += t;
    			if (mp[x].size()) {
    				stk.push(mp[x].front());
    				mp[x].pop_front();
    			}
    		}
    	} else {
    		if (stk.size()) {
    			char t = stk.top();
    			ans += t;
    			stk.pop();
    		}
    	}
    }
    std::cout << ans << "\n";
    
    return 0;
}

L2-038 病毒溯源

思路:

  • 其实也可以用 dfs,求出深度最大的点即可,然后倒着找path

时间复杂度: O ( n k ) O(nk) O(nk)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> deg(N), path(N);
    std::vector<std::vector<int>> adj(N);
    for (int i = 0; i < N; i++) {
        int k;
        std::cin >> k;

        for (int j = 0; j < k; j++) {
            int x;
            std::cin >> x;
            deg[x]++;
            path[x] = i;
            adj[i].push_back(x);
        }
        std::sort(adj[i].begin(), adj[i].end());
    }
    int u = 0;
    for (int i = 0; i < N; i++) {
        if (!deg[i]) u = i;
    }

    int ans = 0, mx = 0;
    // bfs or dfs
    // bfs version
    std::queue<std::pair<int, int>> q;
    q.push({u, 1});
    while (!q.empty()) {
        auto [x, dep] = q.front();
        q.pop();

        if (dep > mx) {
            mx = dep;
            ans = x;
        }
        for (int e : adj[x]) {
            q.push({e, dep + 1});
        }
    }
    /* dfs version
    auto dfs = [&](auto self, int u, int dep) -> void {
        if (dep > mx) {
            mx = dep;
            ans = u;
        }
        for (auto x : adj[u]) {
            self(self, x, dep + 1);
        }
    };
    dfs(dfs, u, 1);
    */
    std::cout << mx << "\n";
    std::vector<int> p;
    while (ans != u) {
        p.push_back(ans);
        ans = path[ans];
    }
    p.push_back(u);
    for (int i = 0; i < p.size(); i++) {
        std::cout << p[p.size() - i - 1] << " \n"[i == p.size() - 1];
    }
    
    return 0;
}

L2-039 清点代码库

思路:

  • 就是计算有多少个序列是重复的,直接用map维护即可

时间复杂度: O ( n ( l o g n + m ) ) O(n(logn + m)) O(n(logn+m))

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M;
    std::cin >> N >> M;

    std::map<std::vector<int>, int> mp;
    std::vector<std::vector<int>> a(N, std::vector<int>(M));
    for (int i = 0; i < N; i++) {
    	for (int j = 0; j < M; j++) {
    		std::cin >> a[i][j];
    	}
    	mp[a[i]]++;
    }

    std::vector<std::pair<int, std::vector<int>>> ans;
    for (auto [x, y] : mp) {
    	ans.push_back({y, x});
    }

    std::cout << ans.size() << "\n";
    std::sort(ans.begin(), ans.end(), [&](auto i, auto j) {
    	if (i.first != j.first) {
    		return i.first > j.first;
    	}
    	return i.second < j.second;
    });

    for (auto [x, y] : ans) {
    	std::cout << x << " ";
    	for (int i = 0; i < y.size(); i++) {
    		std::cout << y[i] << " \n"[i == y.size() - 1];
    	}
    }

    return 0;
}

L2-040 哲哲打游戏

思路:

  • 模拟即可,做一个结构体来存每次的存档情况,然后按照题目意思模拟

时间复杂度: O ( n k ) O(nk) O(nk)

struct node {
    int pos;
    std::vector<int> path;
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M;
    std::cin >> N >> M;

    std::vector<std::vector<int>> adj(N + 1);
    for (int i = 0; i < N; i++) {
        int K;
        std::cin >> K;
        for (int j = 0; j < K; j++) {
            int x;
            std::cin >> x;

            adj[i + 1].push_back(x);
        }
    }
    
    int now = 1;
    std::vector<int> tmp(1, 1);
    std::vector<node> save(105);
    for (int i = 0; i < M; i++) {
        int op, x;
        std::cin >> op >> x;

        if (op == 0) {
            tmp.push_back(adj[now][x - 1]);
            now = adj[now][x - 1];
        } else if (op == 1) {
            save[x].pos = now;
            save[x].path = tmp;
            std::cout << now << "\n";
        } else {
            now = save[x].pos;
            tmp = save[x].path;
        }
    }
    std::cout << tmp.back() << "\n";

    return 0;
}

L2-041 插松枝

思路:

  • tree[N]代表每一个松针数组,bot代表盒子,我们需要按照题目的意思模拟
  • 但需要特别注意的是,最后一定要把盒子清空,结束的时候,盒子里不能有任何松针

时间复杂度: O ( N ) O(N) O(N)

constexpr int N = 1010;
std::vector<int> tree[N];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M, K;
    std::cin >> N >> M >> K;

    std::vector<int> a(N);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i];
    }

    int tot = 1;
    std::deque<int> bot;
    for (int i = 0; i < N; i++) {
        if (tree[tot].size() == K) {
            tot++;
        }
        if (bot.empty()) {
            if (tree[tot].empty()) {
                tree[tot].push_back(a[i]);
            } else if (tree[tot].back() >= a[i]) {
                tree[tot].push_back(a[i]);
            } else {
                bot.push_back(a[i]);
            }
        } else if (bot.size() < M) {
            if (tree[tot].empty()) {
                int tmp = bot.back();
                bot.pop_back();
                tree[tot].push_back(tmp);
                i--;
            } else if (bot.back() <= tree[tot].back()) {
                int tmp = bot.back();
                bot.pop_back();
                tree[tot].push_back(tmp);
                i--;
            } else if (bot.back() > tree[tot].back()) {
                if (a[i] <= tree[tot].back()) {
                    tree[tot].push_back(a[i]);
                } else {
                    bot.push_back(a[i]);
                }
            }
        } else if (bot.size() == M) {
            if (tree[tot].empty()) {
                int tmp = bot.back();
                bot.pop_back();
                tree[tot].push_back(tmp);
                i--;
            } else if (bot.back() <= tree[tot].back()) {
                int tmp = bot.back();
                bot.pop_back();
                tree[tot].push_back(tmp);
                i--;
            } else if (bot.back() > tree[tot].back()) {
                if (a[i] <= tree[tot].back()) {
                    tree[tot].push_back(a[i]);
                } else {
                    tot++;
                    i--;
                }
            }
        }
    }
    while (bot.size()) {
        if (tree[tot].empty() || bot.back() <= tree[tot].back()) {
            tree[tot].push_back(bot.back());
            bot.pop_back();
        } else {
            tot++;
        }
        if (tree[tot].size() == K) tot++;
    }
    for (int i = 1; i <= tot; i++) {
        if (tree[i].size()) {
            for (int j = 0; j < tree[i].size(); j++) {
                std::cout << tree[i][j] << " \n"[j == tree[i].size() - 1];
            }
        }
    }
    return 0;
}

L2-042 老板的作息表

思路:

  • 可以根据题意,设置起始时间 00:00:00 和终止时间 23:59:59,然后将题目所给的时间排序,然后开始匹配,当找到头部相等,就更新头部信息 → \rightarrow 当前位置的结束时间,最后如果结束时间不等于这一天的最后时刻,就直接输出最后的时间到最后的时刻

时间复杂度: O ( N ) O(N) O(N)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::string c;
    std::vector<std::pair<std::string, std::string>> a(N);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i].first >> c >> a[i].second;
    }

    std::sort(a.begin(), a.end(), [&](auto i, auto j) {
        return i.first < j.first;
    });
    std::string start = "00:00:00", end = "23:59:59";
    for (int i = 0; i < N; i++) {
        if (a[i].first == start) {
            start = a[i].second;
        } else {
            std::cout << start << " - " << a[i].first << "\n";
            start = a[i].second;
        }
    }
    if (start != end) {
        std::cout << start << " - " << end << "\n";
    }

    return 0;
}

L2-043 龙龙送外卖

思路:

  • 快递站是一颗树,我们求每一个节点到root节点的深度,然后当增加一个外卖站点(节点),我们需要走的距离为计算从 x x x x x x 所在的最远祖先(第一个被访问过的祖先)的路径长度 Σ i = 0 M n o d e n e w − n o d e l a s t − m a x ( n o d e i ) \Sigma_{i=0}^{M}node_{new} - node_{last} - max(node_{i}) Σi=0Mnodenewnodelastmax(nodei)

时间复杂度: O ( N + M × D e p t h t r e e ) O(N + M \times Depth_{tree}) O(N+M×Depthtree)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M;
    std::cin >> N >> M;

    std::vector<int> p(N + 1);
    std::vector<std::vector<int>> adj(N + 1);
    for (int i = 1; i <= N; i++) {
        int x;
        std::cin >> x;

        if (x < 0) {
            p[0] = i;
        } else {
            adj[x].push_back(i);
        }
        p[i] = x;
    }
	// bfs or dfs
    std::vector<int> vis(N + 1), dist(N + 1);
    vis[p[0]] = 1;
    // bfs 
    std::queue<std::pair<int, int>> q;
    q.push({p[0], 0});
    while (!q.empty()) {
        auto [now, dep] = q.front();
        q.pop();

        dist[now] = dep;
        for (int x : adj[now]) {
            q.push({x, dep + 1});
        }
    }
    // dfs
    auto dfs = [&](auto self, int u, int dep) -> void {
        dist[u] = dep;
        for (auto x : adj[u]) {
            self(self, x, dep + 1);
        }
    };
    dfs(dfs, p[0], 0);

    int res = 0, lst = 0, max = 0;
    for (int i = 0; i < M; i++) {
        int x;
        std::cin >> x;

        lst = x;
        while (!vis[lst]) { // 访问所有点了的外卖至少一次
            vis[lst] = 1;
            lst = p[lst];
        }
        res += dist[x] - dist[lst];
        max = std::max(max, dist[x]);
        std::cout << res * 2 - max << "\n";
    }

    return 0;
}

L2-044 大众情人

思路:

  • 我们设 2 个集合,分别存男性和女性编号,然后用dist[i][Fri]来存储当前这个人i到朋友Fri之间的距离,然后可以使用 Floyd最短路来跑一遍,来计算每个人之间的最短距离
  • 由于题目中的“异性缘”的定义规则为:我们记一个人 i i i 在一个异性 j j j 眼中的距离感为 D i j D_{ij} Dij,将 i i i 的“异性缘”定义为 1 / m a x j ∈ S ( i ) { D i j } 1/max_{j∈S(i)}\{D_{ij}\} 1/maxjS(i){Dij},其中 S ( i ) S(i) S(i) 是相对于 i i i 的所有异性的集合。
  • 所以我们可以直接暴力枚举两个集合,然后求出当前异性缘最大的那个人的编号

时间复杂度: O ( N 3 ) O(N^3) O(N3)

constexpr int inf = 1E9;

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    std::vector<int> male, female;
    std::vector<std::vector<int>> dist(N + 1, std::vector<int>(N + 1, inf));
    for (int i = 1; i <= N; i++) {
    	int K;
    	char C;
    	std::cin >> C >> K;
    	if (C == 'F') {
    		female.push_back(i);
    	} else {
    		male.push_back(i);
    	}
    	for (int j = 0; j < K; j++) {
    		int Fri, d;
    		std::cin >> Fri >> C >> d;
    		dist[i][Fri] = d;
    	}
    }

    for (int k = 1; k <= N; k++) {
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			dist[i][j] = std::min(dist[i][k] + dist[k][j], dist[i][j]);
    		}
    	}
    }

    auto get = [&](auto &find, auto &base, auto &target, int mark = 0) {
    	for (int i = 0, score = 0; i < find.size(); i++, score = 0) {
    		for (int j = 0; j < base.size(); j++) {
    			score = std::max(score, dist[base[j]][find[i]]);
    		}
    		target[score].insert(find[i]);
    	}
    	for (auto x : target.begin()->second) {
    		if (mark++) std::cout << " ";
    		std::cout << x;
    	}
    };
    
    std::map<int, std::set<int>> Fans, Mans;
    get(female, male, Fans);
    std::cout << "\n";
    get(male, female, Mans);
    
    return 0;
}

L2-045 堆宝塔

思路:

  • 用栈模拟圈的上下移动即可

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

constexpr int N = 10010;
std::vector<int> v[N];
int a[N];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }

    std::stack<int> s;
    int p = 0;
	v[p].push_back(a[0]);
    for (int i = 1; i < n; i++) {
        if (v[p].size() && a[i] < v[p].back()) { // 如果比下面的那个圈小
            v[p].push_back(a[i]);
        } else if (v[p].size() && a[i] >= v[p].back()) { // 如果比下面那个圈大,
            if (s.empty() || (s.size() && a[i] > s.top())) s.push(a[i]); // 如果B柱子为空
            else if (s.size() && a[i] <= s.top()) {
                p++;
                while (s.size() && s.top() > a[i]) {
                    v[p].push_back(s.top());
                    s.pop();
                }
                v[p].push_back(a[i]);
            }
        }
    }
    if (s.size()) p++;
    std::cout << p + 1 << ' ';
    
    int mx = s.size();
    for (int i = 0; i <= p; i++) {
        mx = std::max(mx, (int)v[i].size());
    }

    std::cout << mx;
    return 0;
}

L2-046 天梯赛的赛场安排

思路:

  • BFS 模拟,在优先队列(大根堆)里,先分配数量多的,然后分配数量少的

时间复杂度: O ( N l o g N ) O(NlogN) O(NlogN)

constexpr int N = 250010;
int room[N];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, C;
    std::cin >> N >> C;

    std::vector<std::string> s(N);
    std::priority_queue<std::pair<int, std::string>> q;
    for (int i = 0; i < N; i++) {
        int x;
        std::cin >> s[i] >> x;
        q.push({x, s[i]});
    }
    
    int tot = 0, ok = 0;
    std::map<std::string, int> mp;
    while (q.size()) {
        auto [cur, t] = q.top();
        q.pop();

        mp[t]++;
        if (cur >= C) {
            room[++tot] = 0;
            if (cur != C) {
                q.push({cur - C, t});
            }
        } else {
            ok = false;
            for (int i = 1; i <= tot; i++) {
                if (room[i] >= cur) {
                    room[i] -= cur;
                    ok = true;
                    break;
                }
            }
            if (!ok) {
                room[++tot] = C - cur;
            }
        }
    }
    int sum = 0;
    for (int i = 0; i < N; i++) {
        std::cout << s[i] << " " << mp[s[i]] << "\n";
    }
    std::cout << tot << "\n";
    
    return 0;
}

L2-047 锦标赛

思路:

时间复杂度: O ( k × 2 k ) O(k \times 2^k) O(k×2k)

constexpr int N = 50, M = 1 << 20;
int id[N][M];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int k;
    std::cin >> k;

    bool ok = true;
    std::vector<int> ans(M);
    std::vector<std::vector<int>> a(k + 1);
    for (int i = 1; i <= k; i++) {
        int n = 1 << (k - i);
        a[i].resize(n);
        for (int j = 0; j < n; j++) {
            std::cin >> a[i][j];
            if (i == 1) {
                ans[j << 1] = a[i][j];
                id[i][j] = (j << 1 | 1);
                continue ;
            }
            int max = std::max(a[i][j], std::max(a[i - 1][j << 1], a[i - 1][j << 1 | 1]));
            if (a[i][j] < a[i - 1][j << 1] && a[i][j] < a[i - 1][j << 1 | 1]) {
                ok = false;
                break;
            } else if (a[i][j] >= a[i - 1][j << 1]) {
                ans[id[i - 1][j << 1]] = a[i][j];
                id[i][j] = id[i - 1][j << 1 | 1];
            } else {
                ans[id[i - 1][j << 1 | 1]] = a[i][j];
                id[i][j] = id[i - 1][j << 1];
            }
            a[i][j] = max;
        }
    }

    int w;
    std::cin >> w;

    if (a[k][0] > w) {
        ok = false;
    } else {
        ans[id[k][0]] = w;
    }
    if (!ok) {
        std::cout << "No Solution\n";
    } else {
        for (int i = 0; i < (1 << k); i++) {
            std::cout << ans[i] << " \n"[i == (1 << k)];
        }
    }
    
    return 0;
}

L2-048 寻宝图

思路:

  • 直接 BFS 搜一下即可

时间复杂度: O ( n × m ) O(n \times m) O(n×m)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
	
	int n, m;    
    std::cin >> n >> m;

    std::vector<std::vector<char>> g(n, std::vector<char> (m, 0));
    std::vector<std::vector<int>> st(n, std::vector<int> (m, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            std::cin >> g[i][j];
        }
    }

    bool flag = false;
    const int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
    auto bfs = [&] (int x, int y) {
        std::queue<std::pair<int, int>> q;
        q.push({x, y});
        st[x][y] = 1;

        while (q.size()) {
            auto t = q.front();
            q.pop();

            if (g[t.first][t.second] >= '2' && g[t.first][t.second] <= '9') flag = true;
            for (int i = 0; i < 4; i++) {
                int a = dx[i] + t.first, b = dy[i] + t.second;
                if (a < 0 || b < 0 || a >= n || b >= m || st[a][b]) continue;
                if (g[a][b] == '0') continue;
                st[a][b] = 1;
                q.push({a, b});
            }
        }
    };
    int ans = 0, res = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (!st[i][j] && g[i][j] != '0') {
                bfs(i, j);
                ans++;
                if (flag) {
                    res++;
                }
                flag = false;
            }
        }
    }
    std::cout << ans << ' ' << res << '\n';
    return 0;
}

L2-049 鱼与熊掌

思路:

  • 直接开mset即可,假设xy是询问的两个物品,那么我们只需要枚举集合x中的人员,与y中的相同的数量即可

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n, m;
    std::cin >> n >> m;

    std::set<int> st[m + 1];
    for (int i = 0; i < n; i++) {
        int k;
        std::cin >> k;

        for (int j = 0; j < k; j++) {
            int x;
            std::cin >> x;
            st[x].insert(i);
        }
    }

    int Q;
    std::cin >> Q;

    while (Q--) {
        int x, y;
        std::cin >> x >> y;

        int ans = 0;
        for (auto v : st[x]) {
            if (st[y].count(v)) {
                ans++;
            }
        }
        std::cout << ans << "\n";
    }

    return 0;
}

L2-050 懂蛇语

思路:

  • 如果按照题目意思模拟,不考虑一句话的前面是否存在空格,就会在第二个点出现格式错误,所以我们要先将前面的空格去除,然后存储的时候,需要把前面删除的空格给补回来

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

signed main() {
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;

    getchar();

    std::map<std::string, std::vector<std::string>> mp;
    for (int i = 0; i < N; i++) {
        std::string s;
        std::getline(std::cin, s);

        int l = 0;
        while (s[l] == ' ') {
            l++;
        }
        s = s.substr(l);
        std::vector<std::string> vec;
        for (int j = 0; j < s.size(); j++) {
            int k = j, len = 0;
            while (k < s.size() && s[k] != ' ') {
                k++;
                len++;
            }
            while (s[k] == ' ') {
                k++;
            }
            std::string t = s.substr(j, len);
            vec.push_back(t);
            j = k - 1;
        }
        std::string tmp;
        for (int j = 0; j < vec.size(); j++) {
            tmp += vec[j][0];
        }
        if (l != 0) {
            while (l--) {
                s = ' ' + s;
            }
        }
        mp[tmp].push_back(s);
    }

    int M;
    std::cin >> M;

    getchar();

    for (int i = 0; i < M; i++) {
        std::string s;
        std::getline(std::cin, s);

        int l = 0;
        while (s[l] == ' ') {
            l++;
        }
        s = s.substr(l);
        std::vector<std::string> vec;
        for (int j = 0; j < s.size(); j++) {
            int k = j, len = 0;
            while (k < s.size() && s[k] != ' ') {
                k++;
                len++;
            }
            while (s[k] == ' ') {
                k++;
            }
            std::string t = s.substr(j, len);
            vec.push_back(t);
            j = k - 1;
        }
        std::string tmp;
        for (int j = 0; j < vec.size(); j++) {
            tmp += vec[j][0];
        }
        if (!mp.count(tmp)) {
            std::cout << s << "\n";
        } else {
            if (mp[tmp].size() == 1) {
                std::cout << mp[tmp][0] << "\n";
            } else {
                int tot = 0;
                std::sort(mp[tmp].begin(), mp[tmp].end());
                for (auto x : mp[tmp]) {
                    if (++tot != mp[tmp].size()) {
                        std::cout << x << "|";
                    } else {
                        std::cout << x << "\n";
                    }
                }
            }
        }
    }

    return 0;
}

L2-051 满树的遍历

思路:

  • 只需要知道一颗树怎么存以及树的前序遍历即可,没啥难的地方

时间复杂度: O ( n ) O(n) O(n)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;

    int root = 0;
    std::vector<int> deg(n + 1);
    std::vector<std::vector<int>> adj(n + 1);
    for (int i = 1; i <= n; i++) {
    	int x;
    	std::cin >> x;

    	if (x == 0) {
    		root = i;
    	}

    	adj[x].push_back(i);
    	deg[x]++;
    }

    std::set<int> st;
    for (int i = 1; i <= n; i++) {
    	st.insert(deg[i]);
    }
    if (st.size() == 2 || n == 1) {
    	std::cout << *--st.end() << " " << "yes\n";
    } else {
    	std::cout << *--st.end() << " " << "no\n";
    }

    int tot = 0;
    auto dfs = [&](auto self, int u) -> void {
    	std::cout << u << " \n"[++tot == n];
    	for (int x : adj[u]) {
    		self(self, x);
    	}
    };
    dfs(dfs, root);

    return 0;
}

L2-052 吉利矩阵

思路:

  • 我们将问题改变为存储每一行每一列的值,其中row[i]col[i]分别表示第i行与第i列的和,然后我们开始暴搜

时间复杂度: O ( N L ) O(N^L) O(NL)

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int L, N;
    std::cin >> L >> N;

    int ans = 0;
    std::vector<int> row(N + 1), col(N + 1);
    auto dfs = [&](auto self, int x, int y) {
        if (x == N + 1) {
            ans++;
            return ;
        }
        for (int i = 0; i <= L; i++) {
            row[x] += i;
            col[y] += i;
            if (row[x] <= L && col[y] <= L) {
                int v = 0; // 剪枝优化
                if (x == N) {
                    if (col[y] == L) {
                        v++;
                    }
                } else {
                    v++;
                }
                if (y == N) {
                    if (row[x] == L) {
                        v++;
                    }
                } else {
                    v++;
                }
                if (v == 2) {
                    self(self, x + (y / N), y % N + 1);
                }
            }
            col[y] -= i;
            row[x] -= i;
        }
    };
    dfs(dfs, 1, 1);

    std::cout << ans << "\n";

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值