2024 CCPC邀请赛(山东)部分题解 (The 2024 CCPC Shandong Invitational Contest)

A. Printer

#include <bits/stdc++.h>

using i64 = long long;

void Solve() {
    int n, K;
    std::cin >> n >> K;

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

    auto check = [&](i64 mid) -> bool {
        i64 ans = 0;
        for (int i = 0; i < n; ++i) {
            i64 T = 1LL * t[i] * l[i] + w[i];
            ans += mid / T * l[i];
            ans += std::min((mid % T) / t[i], 1LL * l[i]);
            if (ans >= K) {
                return true;
            }
        }
        return false;
    };

    i64 lo = 0, hi = 2e18;
    while (lo < hi) {
        i64 mid = (lo + hi) / 2;
        if (check(mid)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }
    std::cout << lo << '\n';
}

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

    int t;
    std::cin >> t;

    for (int ti = 1; ti <= t; ++ti) {
        // std::cerr << "Solve : " << ti << '\n';
        Solve(); 
    }

    return 0;
}

C. Colorful Segments 2

#include <bits/stdc++.h>

using i64 = long long;

constexpr int P = 998244353;

void Solve() {
    int n, K;
    std::cin >> n >> K;

    std::map<int, std::array<int, 2>> f;
    i64 ans = 1;
    for (int i = 0; i < n; ++i) {
        int l, r;
        std::cin >> l >> r;
        f[l][0]++;
        f[r + 1][1]++;
    }

    for (auto [_, v] : f) {
        for (int i = 0; i < v[1]; ++i) {
            K++;
        }
        for (int i = 0; i < v[0]; ++i) {
            ans = ans * std::max(0, K) % P;
            K--;
        }
    }

    std::cout << ans << '\n';
}

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

    int t;
    std::cin >> t;

    for (int ti = 1; ti <= t; ++ti) {
        // std::cerr << "Solve : " << ti << '\n';
        Solve(); 
    }

    return 0;
}

D. Hero of the Kingdom

设这次交易能获得 k ∗ ( q − p ) k*(q-p) k(qp) 的利润,我们对每一种 k k k一起处理,复杂度 O ( 1 ) O(1) O(1)
而不同的 k k k总共有不到 t \sqrt{t} t 种,故复杂度为 O ( t ) O(\sqrt{t}) O(t )

#include <bits/stdc++.h>

using i64 = long long;

void Solve() {
    i64 p, a, b, q, c, d, m, t;
    std::cin >> p >> a >> b >> q >> c >> d >> m >> t;
    
    while (true) {
        i64 buy = m / p;
        if (buy <= 0) {
            break;
        }

        i64 time = a * buy + b + c * buy + d;
        // increase coins
        i64 inc = (q - p) * buy;
        i64 lev = (buy + 1) * p;
        i64 round = (lev - m + inc - 1) / inc;

        i64 totime = time * round;
        if (t >= totime) {
            t -= totime;
            m += round * inc;
        } else {
            i64 k = t / time;
            m += k * inc;
            t %= time;
            
            t -= (b + d);
            if (t <= 0) {
                break;
            }
            m += t / (a + c) * (q - p);
            break;
        }
    }

    std::cout << m << '\n'; 
}

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

    int t;
    std::cin >> t;

    for (int ti = 1; ti <= t; ++ti) {
        // std::cerr << "Solve : " << ti << '\n';
        Solve(); 
    }

    return 0;
}

E.Sensors

思考一个问题:如果询问改成离线,应该怎么做?

我们需要查询每个区间最晚的和第二晚变色的球,运用线段树即可做到 O ( l o g ( n ) ) O(log(n)) O(log(n))查询
本题为强制在线,需要另辟蹊径。

观察到区间为一开始给定,我们把 [ l , r ] [l,r] [l,r]这个区间下放到线段树上,把 [ l , r ] [l,r] [l,r]划分为 k k k个子区间: [ l 1 , r 1 ] , [ l 2 , r 2 ] . . . [ l k , r k ] [l_1,r_1],[l_2,r_2]...[l_k,r_k] [l1,r1],[l2,r2]...[lk,rk],而 k ≤ 2 ∗ l o g ( n ) k\le2*log(n) k2log(n),并将这 k k k个子区间打上标记。

接下来进行到修改操作,注意到一次修改影响到最多 l o g ( n ) log(n) log(n)个子区间

对于每个子区间,我们记 c n t cnt cnt为子区间剩余红球数量,在变色修改时更新 c n t cnt cnt
c n t < 2 cnt<2 cnt<2的时候,我们需要传递信息给所有的标记区间,

如果标记区间剩下恰好一个红球,则计入答案(这部分看代码会更方便理解)

由于每个子区间传递次数不超过两次,而子区间总数 < 4 n <4n <4n,故时间复杂度为 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(nlog(n))

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 5e5 + 5;

int n, m;
int L[N], R[N];
int cnt[N * 4];
int res[N];
std::vector<int> Q[N * 4]; // Interval id

#define lc (p << 1)
#define rc (p << 1 | 1)
#define mid ((l + r) >> 1)
#define lson lc, l, mid
#define rson rc, mid + 1, r
void build(int p, int l, int r) {
    cnt[p] = r - l + 1; // less than 2
    Q[p].clear();
    if (l == r) {
        return;
    }
    build(lson);
    build(rson);
}

void modify(int p, int l, int r, int x) {
    if (R[x] < l || r < L[x]) return;
    if (L[x] <= l && r <= R[x]) {
        if (l == r) {
            res[x] += 1;
        } else {
            res[x] += 2;
        }
        Q[p].push_back(x);  
        return;
    }
    modify(lson, x);
    modify(rson, x);
}

i64 ans;
void update(int p, int l, int r, int x) {
    --cnt[p];
    if (cnt[p] < 2) {
        for (auto i : Q[p]) {
            --res[i];
            if (res[i] == 1) {
                ans += 1LL * i * i;
            }
            if (res[i] == 0) {
                ans -= 1LL * i * i;
            }
        }
    }
    if (l == r) return;
    if (x <= mid) {
        update(lson, x);
    } else {
        update(rson, x);
    }
}

void Solve() {
    std::cin >> n >> m;
    build(1, 0, n - 1); 
    
    ans = 0;
    for (int i = 1; i <= m; ++i) {
        res[i] = 0;
        std::cin >> L[i] >> R[i];
        modify(1, 0, n - 1, i);
        if (res[i] == 1) {
            ans += 1LL * i * i;
        }
    }

    std::cout << ans << ' ';    
    for (int i = 0; i < n; ++i) {
        int x;
        std::cin >> x;
        x = (x + ans) % n;
        // std::cerr << "query : " << x << '\n';
        
        update(1, 0, n - 1, x);
        std::cout << ans << ' ';
    }
    std::cout << '\n';
}

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

    int t;
    std::cin >> t;

    for (int ti = 1; ti <= t; ++ti) {
        // std::cerr << "Solve : " << ti << '\n';
        Solve();
    }

    return 0;
}

F.Divide the Sequence

#include <bits/stdc++.h>

using i64 = long long;

void Solve() {
    int n;
    std::cin >> n;

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

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

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

    int t;
    std::cin >> t;

    for (int ti = 1; ti <= t; ++ti) {
        // std::cerr << "Solve : " << ti << '\n';
        Solve(); 
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值