1594 字
8 分钟
2024-2025 ICPC NERC, Kyrgyzstan Qualification Contest

题目链接#

2024-2025 ICPC NERC, Kyrgyzstan Qualification Contest

A. Problem Statement#

题意#

nn 行字符串,问输入了几个回车

题解#

输出 n1n-1

代码#

void idol_produce(int testCase) { 
    /*Code Here*/
    int n;
    cin >> n;
    cout << n - 1 << '\n';
}

B. Ant Hill#

题意#

给定 nn 个数表示蚂蚁山中,蚂蚁的进出,蚂蚁山在任何时刻蚂蚁的数量都不为负数,求最开始至少有几只蚂蚁

题解#

从头开始模拟蚂蚁的进出,设 resres 为当前蚂蚁山的数量,ans=min{resres0}ans = -\min\{res | res \leq 0\}

代码#

void idol_produce(int testCase) { 
    /*Code Here*/
    int n;
    cin >> n;
    ll ans = 0;
    ll p = 0;
    for(int i = 1;i <= n; i++){
        ll x;
        cin >> x;
        p += x;
        if(p <= 0) ans = max(ans, -p);
    }
    cout << ans << '\n';
}

C. Linear Maze#

题意#

nn 个房间,每次可以从房间 nn 转移到房间 n+1n + 1,有 kk 个特殊房间,如果在奇数次访问这样一个房间,下一步则会传送到房间 11,问离开迷宫要经过几个房间

题解#

当访问到普通房间时,步数 + 1,如果访问到特殊房间,则步数 + 1后翻倍,显然访问到特殊房间后,回到该房间需要重新走相同的路程

代码#

void idol_produce(int testCase) { 
    /*Code Here*/
    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1);
    for(int i = 1;i <= k; i ++){
        int x;
        cin >> x;
        a[x] = 1;
    }
    ll ans = 0;
    for(int i = 1;i <= n; i++){
        ans ++;
        if(a[i]) ans *= 2;
    }
    cout << ans << '\n';
}

D. Grouping#

题意#

nn 个数字分为最小数目的好数集,好数集的定义如下:

  1. 集合的大小不超过 kk

  2. 集合的最大值和最小值之差不超过 MM

题解#

排序原数组,贪心地将其放入当前集合中,若满足则放入,否则另开一个新集合

代码#

void idol_produce(int testCase) {
    /*Code Here*/
    int n, m, k;
    cin >> n >> m >> k;
    vector<ll> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    sort(a.begin(), a.end());
    ll num = -INF;
    int cnt = m;
    int ans = 0;
    for (int i = 0; i < n; i++) {
        if (cnt == k) {
            cnt = 1;
            num = a[i];
            ans++;
        } else if (a[i] - num > m) {
            cnt = 1;
            num = a[i];
            ans++;
        } else {
            cnt++;
        }
    }
    cout << ans << endl;
}

H. Hierarchy#

题意#

给定几个公司的员工架构树,求员工数量最多的一个公司

题解#

DFS求每个树的大小即可

代码#

void idol_produce(int testCase) {
    /*Code Here*/
    int n;
    cin >> n;
    vector<vector<int> > son(n + 1);
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        son[x].push_back(i);
    }
    vector<int> dp(n + 1, 0);
    int ans = 0;
    int maxn = 0;
    function<void(int)> dfs = [&](int u) {
        if (son[u].empty()) {
            dp[u] = 1;
            return;
        }
        for (auto v : son[u]) {
            dfs(v);
            dp[u] += dp[v];
            if (u == 0 && dp[v] > maxn) {
                maxn = dp[v];
                ans = v;
            }
        }
        dp[u] += 1;
    };
    dfs(0);
    cout << ans << ' ' << maxn << endl;
}

I. Study Day#

题意#

参加 nn 次讲座,每次可以获得 aia_i 点知识点,可以在参加前进行冥想使得这次获得的知识点翻倍,不能连续冥想两次,问知识点最多为多少?

题解#

dpm(i)dp_m(i) 表示第 ii 次未冥想获得的最多知识点,dpo(i)dp_o(i) 表示第 ii 次冥想获得的最多的知识点,那么满足:

dpm(i)=max(dpo(i1),dpm(i1))+aidpo(i)=dpm(i1)+2×aidp_m(i) = \max(dp_o(i - 1), dp_m(i - 1)) + a_i \\ dp_o(i) = dp_m(i-1) + 2 \times a_i

代码#

void idol_produce(int testCase) {
    /*Code Here*/
    int n;
    cin >> n;
    vector<vector<ll> > dp(2, vector<ll>(n + 1));
    vector<string> ans(2);
    for (int i = 1; i <= n; i++) {
        ll x;
        cin >> x;
        auto tmp = ans;
        if (dp[0][i - 1] > dp[1][i - 1]) {
            dp[0][i] = dp[0][i - 1] + x;
            ans[0] = tmp[0] + 'O';
        } else {
            dp[0][i] = dp[1][i - 1] + x;
            ans[0] = tmp[1] + 'O';
        }
        dp[1][i] = dp[0][i - 1] + 2 * x;
        ans[1] = tmp[0] + 'M';
    }
    if (dp[0][n] > dp[1][n]) {
        cout << dp[0][n] << endl;
        cout << ans[0] << endl;
    } else {
        cout << dp[1][n] << endl;
        cout << ans[1] << endl;
    }
}

F. Traffic Lights#

题意#

nn 个路口,到达一个路口花费 aia_i,路口处红灯亮 rir_i 秒,绿灯亮 gig_i 秒,一开始红灯亮了 did_i 秒,求通过所有路口花费的总时间

题解#

timetime 为到达路口时花费的总时间,那么该路口的灯已经亮了 time+ditime + d_i 秒,显然路口的灯以 ri+gir_i + g_i 为周期循环,令 rem=(time+di)mod(ri+gi)rem = (time + d_i) \mod (r_i + g_i) ,当 rem<girem < g_i 时,为绿灯,直接通过,当 rem>rirem > r_i 时为红灯,time:=time+ri+giremtime := time + r_i + g_i - rem

代码#

void idol_produce(int testCase) {
    /*Code Here*/
    int n;
    cin >> n;
    vector<int> a(n + 1), r(n + 1), g(n + 1), d(n + 1);
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    for(int i = 1; i <= n; i++){
        cin >> r[i] >> g[i] >> d[i];
    }
    ll time = 0;
    for(int i = 1;i <= n; i++){
        time += a[i];
        ll t = time + d[i];
        ll rem = t % (r[i] + g[i]);
        if(rem < g[i]){
            continue;
        }
        else{
            time += r[i] + g[i] - rem;
        }
    }
    cout << time << endl;
}

G. Need More Gold#

题意#

nn 个怪物,每个怪物打败需要 bib_i 个金币(不花费),打败后获得 gig_i 个金币,求积累 ww 个金币最少打败怪物的数量和顺序

题解#

维护优先队列,每一次选择当前可打败的价值最高的怪物。

代码#

struct node {
    int id;
    ll x, y;
    bool operator<(const node &rhs) const { return x < rhs.x; }
};
void idol_produce(int testCase) {
    /*Code Here*/
    ll w, n;
    cin >> w >> n;
    vector<node> a(n + 1);
    for (int i = 0; i < n; i++) {
        cin >> a[i].x >> a[i].y;
        a[i].id = i + 1;
    }
    sort(a.begin(), a.end(), [](node a, node b) { return a.y > b.y; });
    priority_queue<node> q;
    vector<int> ans;
    ll now = 0;
    while (!a.empty() && a.back().y == 0) {
        q.push(a.back());
        a.pop_back();
    }
    while (!q.empty() && now < w) {
        node t = q.top();
        q.pop();
        now += t.x;
        ans.emplace_back(t.id);
        while (!a.empty() && a.back().y <= now) {
            q.push(a.back());
            a.pop_back();
        }
    }
    if (now < w) {
        cout << -1 << endl;
        return;
    }
    cout << ans.size() << endl;
    for (auto i : ans) {
        cout << i << " ";
    }
}

E. Mountain Ranges#

题意#

nn 座山,假如相邻两座山之间的高度差不大于 kk,则视为同一座山脉,问最小的 kk 使得恰好划分为 mm 座山脉

题解#

二分 kk,当 ans>mans > m 时,kk 向上二分,否则向上二分

代码#

void idol_produce(int testCase) {
    /*Code Here*/
    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1);
    for(int i = 1;i <= n; i++){
        cin >> a[i];
    }
    if(n == 1){
        cout << 1 << '\n';
        return;
    }
    int l = 1, r = 1e6;
    int ans = -1;
    while(l <= r){
        int mid = (l + r) >> 1;
        int cnt = 1;
        for(int i = 2;i <= n; i++){
            if(abs(a[i] - a[i - 1]) > mid){
                cnt++;
            }
        }
        if(cnt > m){
            l = mid + 1;
        }
        else if(cnt == m){
            ans = mid;
            r = mid - 1;
        }
        else{
            r = mid - 1;
        }
    }
    cout << ans << endl;
}
2024-2025 ICPC NERC, Kyrgyzstan Qualification Contest
https://fuyuki.fun/posts/题解/2024-kyrgyzstan-qualification-contest/
作者
Fuyuki_Vila
发布于
2024-12-27
许可协议
CC BY-NC-SA 4.0