2024 天梯选拔赛(二)

2024 天梯选拔赛(二)

L1-1.□□,□□!

print("yuan shen, qi dong!")

L1-2.比较大小

\(log_22^x = x, \frac{1}{\sqrt x^2} = \frac{1}{x}\),两者比较一下即可

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    double x;
    cin >> x;
    if(x < 1) cout << '<';
    else if(x > 1) cout << '>';
    else cout << '=';

    return 0;
}

L1-3.基于金铲铲的期望学习

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n;
    cin >> n;
    double ans = 0;
    if (n <= 8) ans = 2 * n;
    else ans = n + 8;

    printf("%.2lf",ans/n);

    return 0;
}

L1-4.奇怪的克制倍数

按题意模拟即可

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    double ai, aj, bi, bj;
    cin >> ai >> aj >> bi >> bj;
    double a = 0, b = 0;
    auto df = [](double y, double z) {
        double x = 0 ;
        x = (y + z) / 2;
        if (!y || !z) x /= 2;
        if (y == 2 && z == 2)
        x *= 2;
        return x;
    };
    a = df(ai, aj), b = df(bi, bj);

    printf("%.6lf\n", (a + b) / 2);

    return 0;
}

L1-5.红石难题

把所有红石相连处理出一条直线,对于一个红石信号源,其可以使覆盖边界最小为\(m\)的范围为\(D = (15-m)\times 2 + 1\),即两边加中间,所以答案为\(\lceil \frac{sum}{D} \rceil\),特别的,当\(m\)\(0\)时,输出\(0\);

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

	int n, m;
	cin >> n >> m;
	vector<i64> x(n), y(n);

	i64 sum = 1;
	for (int i = 0; i < n; i ++) {
		cin >> x[i] >> y[i];
		if (i) sum += abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]);
	}
	
    if(!m){
        cout << 0 << '\n';
        return 0;
    }
	int d = (15 - m) * 2 + 1;
	cout << (sum + d - 1) / d << '\n';

	return 0;
}

L1-6.基于文化课的算法学习

记录字符串"main"和"return"数量,两者数量相等时则为代码外,若最后两者不相等或者都没出现过,则为代码有误;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n;
    string s, str;
    cin >> n >> s >> str;

    int ma = 0, re = 0;
    for (int i = 0; i < str.size(); i ++) {
        string t = str.substr(i, s.size());
        if (str.substr(i, 4) == "main") ma ++;
        if (str.substr(i, 6) == "return") re ++;
        if (t == s && ma == re) {
            str[i] = 'z';
            str[i + 1] = 'x';
            str[i + 2] = 'z';
        }
    }

    if (ma != re || (!ma && !re)) {
        cout << "wrong\n";
    } else {
        cout << str << '\n';
    }

    return 0;
}

L1-7.奶茶袋收集

处理出差分数组,可以发现要使得极差最小就是在最大的差值处插入一块板子,将差值大的两者分开,不让它们在同一组;

对差分数组排序,去掉\((m-1)\)个最大的差值即可;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n,m;
    cin >> n >> m;
    vector<int> a(n);
    for(auto &i : a) cin >> i;

    vector<int> res;
    for(int i = 1;i < n;i ++){
        res.push_back(a[i] - a[i - 1]);
    }

    sort(res.begin(),res.end());

    i64 ans = 0;
    for(int i = 0;i < res.size() - m + 1;i ++)
        ans += res[i];

    cout << ans << '\n';

    return 0;
}

L1-8.该加训啦

运用真值表可知\((a\&b)\oplus (a|b) = (a\oplus b)\),即\(f(a,b)=(a\oplus b)\);

根据异或的性质,我们可以求出异或前缀和,通过做差求出区间异或值;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n;
    cin >> n;
    vector<int> a(n + 1), pre(n + 1);

    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        pre[i] = (pre[i - 1] ^ a[i]);
    }

    int m;
    cin >> m;
    while (m --) {
        int l, r;
        cin >> l >> r;
        cout << (pre[r] ^ pre[l-1]) << '\n';
    }

    return 0;
}

L2-1.cy的倒金字塔工厂

按题意运用\(STL\)模拟即可

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n, k;
    cin >> n >> k;
    vector<int> line(n);
    for (auto &i : line) cin >> i;


    stack<int> box, Ta;
    vector<vector<int>> ans;
    vector<int> waste;
    while (box.size() || line.size()) {
        if (line.size()) {
            int x = line.back();
            line.pop_back();
            if (!Ta.size()) {
                Ta.push(x);
            } else {
                int y = Ta.top();
                if (x > y && x - y <= k) {
                    Ta.push(x);
                } else {
                    if (box.size()) {
                        int z = box.top();
                        if (z > y && z - y <= k) {
                            Ta.push(z);
                            box.pop();
                        }
                    }
                    box.push(x);
                }
            }
        } else {
            if (Ta.size() >= 2) {
                vector<int> Pin;
                while (Ta.size()) {
                    Pin.push_back(Ta.top());
                    Ta.pop();
                }
                ans.push_back(Pin);
            } else if (Ta.size() == 1) {
                waste.push_back(Ta.top());
                Ta.pop();
            }
            if (box.size()) {
                while (box.size()) {
                    line.push_back(box.top());
                    box.pop();
                }
                reverse(line.begin(), line.end());
            }
        }
    }
    
    if (Ta.size() >= 2) {
        vector<int> Pin;
        while (Ta.size()) {
            Pin.push_back(Ta.top());
            Ta.pop();
        }
        ans.push_back(Pin);
    } else if (Ta.size() == 1) {
        waste.push_back(Ta.top());
        Ta.pop();
    }

    for (auto ve : ans) {
        for (auto v : ve)
            cout << v << ' ';
        cout << '\n';
    }
    if (waste.size()) {
        for (auto i : waste)
            cout << i << ' ';
        cout << '\n';
    }

    return 0;
}

L2-2.swj学长的精灵融合

按题意模拟出融合的关系可以发现其实就是一颗树,且要求我们从叶子节点往根节点递推;

推出精灵的各等级所需经验后,用\(dfs\)跑一遍树即可;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

struct Node {
    int b, c, d;
};

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

    int n, m;
    cin >> n >> m;

    vector<vector<i64>> jy(4, vector<i64>(110, 1));
    jy[1][1] = jy[2][1] = jy[3][1] = 0;
    for (int i = 3; i <= 100; i ++) {
        jy[1][i] = jy[1][i - 1] + (i - 2);
        jy[2][i] = jy[2][i - 1] + (i - 2) * 2;
        jy[3][i] = jy[3][i - 1] + (i - 2) * 5;
    }

    map<int, vector<Node>> mp;

    for (int i = 0; i < m; i ++) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        mp[a].push_back({b, c, d});
    }

    i64 ans = 0;
    auto dfs = [&](auto self, int x) -> void{
        for (auto [v, c, d] : mp[x]) {
            self(self, v);
            ans += jy[c][d];
        }
    };

    dfs(dfs, n);
    cout << ans << '\n';

    return 0;
}

L2-3.幸运号码

先处理出各字符串的数字和\(sum\),然后把它们的和与其奇偶性关联起来,即用一个二维数组\(cnt[sum[i]][j]\)存储;

对于两个字符串\(S_i,S_j\),如果它们符合要求,即存在一个位置\(pos\)使得\(LeftSum_{pos} = RightSum_{pos}\),如果\(pos\)\(S_i\)中,即可得到\(lsum = (sum[i] - rsum) + sum[j]\),如果\(pos\)\(S_j\)中,那我们只要反着再求一遍即可;

特别的,第一次求的时候如果你计算到了\(S_i\)的边界,那么在反转后求得时候就不能再求\(S_i[0]\),这样会重复计算;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n;
    cin >> n;
    vector<string> s(n);
    vector cnt(111, vector<int>(2));
    vector<i64> sum(n);

    auto get = [](string str) {
        int res = 0;
        for (auto i : str)
            res += (i - '0');
        return res;
    };

    for (int i = 0; i < n; i ++) {
        cin >> s[i];
        sum[i] = get(s[i]);
        cnt[sum[i]][s[i].size() & 1] ++;
    }

    auto solve = [&](vector<string>& s,int f) {
        i64 res = 0;
        for (int i = 0; i < n; i ++) {
            int lsum = 0;
            for (auto j : s[i]) {
                lsum += (j - '0');
                int rsum = sum[i] - lsum;
                if (rsum > lsum) continue;
                res += cnt[lsum - rsum][(s[i].size() + f) & 1];
            }
        }
        return res;
    };

    i64 ans = 0;
    ans += solve(s,0);
    for (auto &i : s)
        reverse(i.begin(), i.end()),i.pop_back();
    ans += solve(s,1);

    cout << ans << '\n';

    return 0;
}

L2-4.恶心的广告

传统的\(BFS\)无法判断在当前位置上还能够打败哪些敌人,所以应该引入\(priority\_queue\)即优先队列来跑\(BFS\);

将敌人的数值作为关键字排序,保证每次\(BFS\)都能够在可走范围内打数值最低的敌人,当最低数值也打不过时则可以退出了;

特别的,对于药剂,我们可以直接获取其数值,然后把它当做数值为\(0\)的敌人再放入队列中;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n, m, x, y, t;
    cin >> n >> m >> x >> y >> t;
    vector mp(n + 1, vector<int>(m + 1));
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            cin >> mp[i][j];

    set<PII> JI;
    for (int i = 0; i < t; i ++) {
        int x, y;
        cin >> x >> y;
        JI.insert({x, y});
    }

    vector vis(n + 1, vector<bool>(m + 1));
    using PIII = pair<int, PII>;
    priority_queue<PIII, vector<PIII>, greater<PIII>> Q;
    int u[] = {1, -1, 0, 0}, v[] = {0, 0, 1, -1};
    i64 ans = 0;

    ans += mp[x][y];
    mp[x][y] = 0, vis[x][y] = 1;
    Q.push({0, {x, y}});

    while (Q.size()) {
        auto [w, loc] = Q.top();
        auto [xi, yi] = loc;
        Q.pop();
        if (w > ans) {
            break;
        }
        ans += w;

        for (int i = 0; i < 4; i ++) {
            int dx = xi + u[i];
            int dy = yi + v[i];
            if (dx >= 1 && dx <= n && dy >= 1 && dy <= m && !vis[dx][dy]) {
                if (JI.count({dx, dy})) {
                    ans += mp[dx][dy];
                    mp[dx][dy] = 0;
                    Q.push({0, {dx, dy}});
                    vis[dx][dy] = 1;
                } else {
                    Q.push({mp[dx][dy], {dx, dy}});
                    vis[dx][dy] = 1;
                }
            }
        }
    }

    cout << ans << '\n';

    return 0;
}

L3-1.Drmeng与商品

\(dp[i][j]\)为前\(i\)个商品中能选出\(j\)组;

按题意即就是一个线性\(dp\),需要我们用前缀和去处理\(i\)\(i-m\)的商品价值;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

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

    int n, m, k;
    cin >> n >> m >> k;
    vector dp(n + 1, vector<i64>(k + 1, -1));
    vector<i64> p(n + 1), sum(n + 1);

    dp[0][0] = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> p[i];
        sum[i] = sum[i - 1] + p[i];
        dp[i][0] = 0;
    }

    for (int i = m; i <= n; i ++) {
        for (int j = 1; j <= k; j ++) {
            dp[i][j] = dp[i - 1][j];
            if (dp[i - m][j - 1] != -1)
                dp[i][j] = max(dp[i][j], dp[i - m][j - 1] + sum[i] - sum[i - m]);
        }
    }

    cout << dp[n][k] << '\n';

    vector<PII> ans;
    int cnt = 1;
    while (k) {
        if (dp[n][k] == dp[n - m][k - 1] + sum[n] - sum[n - m]) {
            ans.emplace_back(n - m + 1, n);
            k --;
            n -= m;
        } else n --;
    }

    for (auto [x, y] : ans)
        cout << x << ' ' << y << '\n';

    return 0;
}

L3-2.黄金树影

读懂题意后就是要求我们求出这棵树的\(dfs\)序,然后用线段树或树状数组查询和修改即可;

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';

using namespace std;
using i64 = long long;

typedef pair<i64, i64> PII;

template<typename T>
struct BIT {
#ifndef lowbit
#define lowbit(x) (x & (-x));
#endif
    int n;
    vector<T> t;

    BIT () {}
    BIT (int _n): n(_n) { t.resize(_n + 1); }
    BIT (int _n, vector<T>& a, vector<T>& w): n(_n) {
        vector<T>(n + 1).swap(t);
        for (int i = 1; i <= n; ++ i) {
            t[i] += w[a[i]];
            int j = i + lowbit(i);
            if (j <= n) t[j] += t[i];
        }
    }
    //单点修改
    void update(int i, T x) {
        while (i <= n) {
            t[i] += x;
            i += lowbit(i);
        }
    }
    //区间查询
    T sum(int i) {
        T ans = 0;
        while (i > 0) {
            ans += t[i];
            i -= lowbit(i);
        }
        return ans;
    }

    T query(int i, int j) {
        return sum(j) - sum(i - 1);
    }
    //区间修改则存入差分数组,[l, r] + k则update(x,k),update(y+1,-k)
    //单点查询则直接求前缀和sum(x)
};

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

    int n, m;
    cin >> n >> m;
    vector<i64> w(n + 1);
    for (int i = 1; i <= n; i ++)
        cin >> w[i];

    vector g(n + 1, vector<int>());
    for (int i = 2; i <= n; i ++) {
        int u;
        cin >> u;
        g[i].push_back(u);
        g[u].push_back(i);
    }

    vector<i64> st(n + 1), ed(n + 1), Xu{0};
    auto dfs = [&](auto self, int u, int fa)->void{
        st[u] = Xu.size();
        Xu.push_back(u);
        for (auto v : g[u]) {
            if (v == fa) continue;
            self(self, v, u);
        }
        ed[u] = Xu.size();
        Xu.push_back(u);
    };

    dfs(dfs, 1, 0);
    BIT<i64> tree(Xu.size(), Xu, w);

    while (m --) {
        i64 op, a, x;
        cin >> op >> a;
        if (op == 1) {
            cin >> x;
            tree.update(st[a], x);
            tree.update(ed[a], x);
        } else {
            cout << tree.query(st[a], ed[a]) / 2 << '\n';
        }
    }

    return 0;
}
posted @ 2024-03-10 15:28  Ke_scholar  阅读(3)  评论(0编辑  收藏  举报