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;
    }
    
  • 相关阅读:
    浏览器组成
    Go!!!
    产假计算器地址
    flex 纵向布局,垂直换行,没有撑开父盒子宽度,求解??
    毕业档案
    进程与线程
    事件循环
    回调地狱
    错误优先回调
    组件 v-if 小心哦
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13676094.html
Copyright © 2011-2022 走看看