zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 95 (Rated for Div. 2)

    传送门

    A. Buying Torches

    签到。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/14 22:39:56
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        ll x, y, k;
        cin >> x >> y >> k;
        ll a = (k * (1 + y) - 1 + x - 2) / (x - 1);
        ll ans = a + k;
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while (T--)
        run();
        return 0;
    }
    

    B. Negative Prefixes

    贪心选即可。

    C. Mortal Kombat Tower

    直接dp就可,一维状态表示当前到第几只boss,再加一维表示谁的回合。然后枚举所有情况转移。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/14 23:00:27
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void chkmin(int& x, int y) {
        if (x > y) x = y;
    }
    void run() {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        vector<vector<int>> dp(n + 1, vector<int>(2, INF));
        dp[0][0] = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 2; j++) if (dp[i][j] != INF) {
                if (j == 0) {
                    chkmin(dp[i + 1][1], dp[i][j] + a[i]);
                    if (i + 2 <= n) {
                        chkmin(dp[i + 2][1], dp[i][j] + a[i] + a[i + 1]);
                    }
                } else {
                    chkmin(dp[i + 1][0], dp[i][j]);
                    if (i + 2 <= n) {
                        chkmin(dp[i + 2][0], dp[i][j]);
                    }
                }
            }
        }
        int ans = min(dp[n][0], dp[n][1]);
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    D. Trash Problem

    仔细一想其实很简单,答案就为最大值-最小值-差值的最大值。
    然后用set什么的维护一下就行。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/14 23:29:47
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        int n, q;
        cin >> n >> q;
        vector<int> a(n);
        for (int i = 0; i < n; i++) 
            cin >> a[i];
        sort(all(a));
        set<int> s;
        multiset<int> t;
        int last = -1;
        ll ans = 0;
        for (int i = 0; i < n; i++) {
            int p = a[i];
            s.insert(p);
            if (last != -1) {
                t.insert(p - last);
                ans += p - last;
            }
            last = p;
        }
        cout << ans - (sz(t) > 0 ? *t.rbegin() : 0) << '
    ';
        while (q--) {
            int op, x;
            cin >> op >> x;
            if (op) {
                auto it = s.lower_bound(x);
                int prev = -1, succ = -1;
                if (it != s.end()) {
                    succ = *it;
                    t.insert(succ - x);
                    ans += succ - x;
                }
                if (it != s.begin()) {
                    --it;
                    prev = *it;
                    t.insert(x - prev);
                    ans += x - prev;
                }
                s.insert(x);
                if (prev != -1 && succ != -1) {
                    t.erase(t.lower_bound(succ - prev));
                    ans -= succ - prev;
                }
            } else {
                auto it = s.upper_bound(x);
                int prev = -1, succ = -1;
                if (it != s.end()) {
                    succ = *it;
                    t.erase(t.lower_bound(succ - x));
                    ans -= succ - x;
                }
                --it;
                if (it != s.begin()) {
                    --it;
                    prev = *it;
                    t.erase(t.lower_bound(x - prev));
                    ans -= x - prev;
                }
                s.erase(x);
                if (prev != -1 && succ != -1) {
                    t.insert(succ - prev);
                    ans += succ - prev;
                }
            }
            cout << ans - (sz(t) > 0 ? *t.rbegin() : 0) << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    E. Expected Damage

    题意:
    (n) 只怪物,每只的攻击力为 (d_i)
    现在有一个防护盾,耐久度为 (a),防御力为 (b)
    现在怪物会随机进行攻击,每个怪物只会攻击一次,规则如下:

    • 如果 (a=0),那么直接造成伤害;
    • 如果 (a>0) 并且 (d_igeq b),那么耐久度减一;
    • 否则什么都没发生。

    现在问所有怪物随机攻击的情况下,期望造成多少伤害。

    思路:
    根据期望的线性性质,考虑每只怪物期望造成的伤害值,那么加起来就为答案。
    我们按照攻击力将怪物分为两类,两类分别来进行处理。
    之后考虑求概率,为成功击中的概率,攻击力较大的怪物的概率为 (1-frac{a}{big});攻击力较小的怪物的概率为 (1-frac{a}{big+1})。然后直接算期望就行。
    这里的概率的计算其实是利用了条件概率的性质。如果各个变量相互独立的情况下,那么我们可以根据某几个特定元素之间的关系来计算出概率,只用考虑我们关注的东西即可。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/15 00:14:40
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5, MOD = 998244353;
     
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
     
    void run() {
        int n, m;
        cin >> n >> m;
        vector<int> a(n);
        for (int i = 0; i < n; i++)
            cin >> a[i];
        sort(all(a));
        vector<ll> pre(n), suf(n);
        pre[0] = a[0];
        for (int i = 1; i < n; i++)
            pre[i] = (pre[i - 1] + a[i]) % MOD;
        suf[n - 1] = a[n - 1];
        for (int i = n - 2; i >= 0; i--) 
            suf[i] = (suf[i + 1] + a[i]) % MOD;
     
        for (int i = 0; i < m; i++) {
            int A, B;
            cin >> A >> B;
            int t = lower_bound(all(a), B) - a.begin();
            int tot = n - t;
            if (tot < A) {
                cout << 0 << '
    ';
                continue;
            }
            int ans = 1ll * (1 - 1ll * A * qpow(tot, MOD - 2) % MOD + MOD) % MOD * suf[t] % MOD;
            if (t) {
                ans = (ans + 1ll * pre[t - 1] * (1 - 1ll * A * qpow(tot + 1, MOD - 2) % MOD + MOD) % MOD) % MOD;
            }
            cout << ans << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    G. Three Occurrences

    题意:
    给定一个序列 (a),问有多少个区间 ([l,r]),满足 (a_l,a_{l+1},cdots,a_r) 中的数刚好出现三次。

    思路:
    问题等价于每个区间中,所有数要么出现 (0) 次要么出现 (3) 次。
    其实可以单独考虑每个数,考虑一个数的情况下,对于每个固定的左端点,右端点哪些合法。手模一下会发现合法的是两段区间,一段是出现 (0) 次的区间,一段是出现 (3) 次的区间。
    那么我们随着左端点的移动,每次只会添加入/删除一个数,也就会影响常数个区间,那么直接用线段树来维护所有合法的区间即可。

    具体来说,我们对于每个数,用 (0) 表示该端点作为右端点合法,(1) 则不合法。那么当左端点枚举到 (l) 时,假设已经更新完,那么所有和为 (0) 的位置就是合法的右端点。那么直接线段树维护最小值记其个数即可。为了方便起见,左端点从右往左进行移动,并且在每个维护值出现位置的vector后面先添加一个 (n+1) 作为哨兵结点。
    细节见代码:

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/15 19:23:18
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5e5 + 5;
     
    int n;
    int a[N];
    int minv[N << 2], cntv[N << 2], lz[N << 2];
    void tag(int o, int l, int r, int v) {
        minv[o] += v;
        lz[o] += v;
    }
     
    void push_up(int o) {
        minv[o] = min(minv[o << 1], minv[o << 1|1]);
        cntv[o] = 0;
        if (minv[o << 1] == minv[o]) cntv[o] = cntv[o << 1];
        if (minv[o << 1|1] == minv[o]) cntv[o] += cntv[o << 1|1];
    }
     
    void push_down(int o, int l, int r) {
        if(lz[o] != 0) {
            int mid = (l + r) >> 1;
            tag(o << 1, l, mid, lz[o]);
            tag(o << 1|1, mid + 1, r, lz[o]);
            lz[o] = 0;   
        }
    }
     
    void build(int o, int l, int r) {
        lz[o] = 0;
        if(l == r) {
            minv[o] = 0;
            cntv[o] = 1;
            return;
        }
        int mid = (l + r) >> 1;
        build(o << 1, l, mid), build(o << 1|1, mid + 1, r);
        push_up(o);
    }
     
    void update(int o, int l, int r, int L, int R, ll v) {
        if(L <= l && r <= R) {
            tag(o, l, r, v);
            return;
        }   
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) update(o << 1, l, mid, L, R, v);
        if(R > mid) update(o << 1|1, mid + 1, r, L, R, v);
        push_up(o);
    }
     
    int query(int o, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            if (minv[o] == 0) return cntv[o];
            return 0;
        }
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        int res = 0;
        if(L <= mid) res = query(o << 1, l, mid, L, R);
        if(R > mid) res += query(o << 1|1, mid + 1, r, L, R);
        return res;
    }
     
    void run() {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        vector<vector<int>> pos(n + 1);
        build(1, 1, n);
     
        for (int i = 1; i <= n; i++) {
            pos[i].emplace_back(n + 1);
        }
        auto Add = [&] (int x, int v) {
            int third = pos[a[x]][sz(pos[a[x]]) - 3];
            int fourth = pos[a[x]][sz(pos[a[x]]) - 4];
            update(1, 1, n, third, fourth - 1, v);
        };
        ll ans = 0;
        for (int l = n; l >= 1; l--) {
            if (sz(pos[a[l]]) >= 4) {
                Add(l, 1);
            }
            pos[a[l]].emplace_back(l);
            if (sz(pos[a[l]]) >= 4) {
                Add(l, -1);
            }
            int second = pos[a[l]][sz(pos[a[l]]) - 2];
            update(1, 1, n, l, second - 1, 1);
            ans += query(1, 1, n, l, n);
        }
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    
  • 相关阅读:
    HDU 5744
    HDU 5815
    POJ 1269
    HDU 5742
    HDU 4609
    fzu 1150 Farmer Bill's Problem
    fzu 1002 HangOver
    fzu 1001 Duplicate Pair
    fzu 1150 Farmer Bill's Problem
    fzu 1182 Argus 优先队列
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13676094.html
Copyright © 2011-2022 走看看