• Educational Codeforces Round 76 (Rated for Div. 2)


    传送门

    A. Two Rival Students

    签到。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/13 22:37:26
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int n, x, a, b;
     
    void run(){
        cin >> n >> x >> a >> b;
        if(a > b) swap(a, b);
        int tmp = min(a - 1, x);
        x -= tmp;
        a -= tmp;
        tmp = min(n - b, x);
        x -= tmp;
        b += tmp;
        cout << b - a << '
    ';
    } 
     
    int main() {
        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. Magic Stick

    分情况讨论一下即可。
    神志不清讨论地很乱

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/13 22:42:05
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int a, b;
     
    void run(){
        cin >> a >> b;
        if(a == 1) {
            if(b == 1) return pt("YES");
            else return pt("NO");
        }
        if(a >= b) return pt("YES");
        if(a > 3) return pt("YES");
        if(b <= 3) return pt("YES");
        pt("NO");
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int t; cin >> t;
        while(t--) run();
    	return 0;
    }
    

    C. Dominated Subarray

    题意:
    给出(n)个数,找到长度最短的区间,满足区间长度大于(1)且存在一个数其出现次数严格大于其它数。

    思路:
    显然最终的答案区间两端点为同一个数,考虑一个这样的区间,如果其不合法,说明存在一个答案更优的区间。
    并且若那个数出现次数超过(2)次,我们选择一个更小的区间使得这个数只出现(2)次,此时有两种情况:一个是合法,那显然答案更优;另一个是不合法,说明答案也可以更优。
    就这样归纳一下,发现答案就是两个相同数的最小间隔。
    然而我神智不清,写了个线段树

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/13 22:49:57
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int n;
    int a[N];
    int pre[N], last[N];
    int maxv[N << 2];
     
    void upd(int o, int l, int r, int p, int v) {
        if(p == 5) dbg(l, r);
        if(l == r) {
            maxv[l] = v;
            return;   
        }
        int mid = (l + r) >> 1;
        if(p <= mid) upd(o << 1, l, mid, p, v);
        else upd(o << 1|1, mid + 1, r, p, v);
        maxv[o] = max(maxv[o << 1], maxv[o << 1|1]);
    }
     
    int query(int o, int l, int r, int L, int R) {
        if(L > R) return 0;
        if(L <= l && r <= R) {
            return maxv[o];
        }   
        int mid = (l + r) >> 1, res = 0;
        if(L <= mid) res = query(o << 1, l, mid, L, R);
        if(R > mid) res = max(res, query(o << 1|1, mid + 1, r, L, R));
        return res;
    }
     
    void build(int o, int l, int r) {
        maxv[o] = 0;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(o << 1, l, mid);
        build(o << 1|1, mid + 1, r);   
    }
     
    void run(){
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i], last[a[i]] = 0;
        if(n == 1) return pt(-1);
        build(1, 1, n);
        for(int i = 1; i <= n; i++) {
            pre[i] = last[a[i]];
            last[a[i]] = i;
            upd(1, 1, n, i, pre[i]);
            dbg(i, pre[i]);
        }
        dbg(query(1, 1, n, 5, 5), pre[5]);
        int ans = INF;
        for(int i = 1; i <= n; i++) {
            if(pre[i]) {
                int L = pre[i] + 1, R = i - 1;
                dbg(i, L, R);
                if(query(1, 1, n, L, R) < L) ans = min(ans, R - L + 3);
            }   
        }
        if(ans == INF) ans = -1;
        cout << ans << '
    ';
    }
     
    int main() {
        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. Yet Another Monster Killing Problem

    题意:
    现在有(n)只怪,每只怪有力量(a_i)
    同时有(n)个英雄,每个英雄有(p_i,s_i)分别代表力量和耐力。
    每一天只能选派一个英雄去打怪兽,每个英雄最多打(s_i)只怪,一个英雄能打败一只怪,当且仅当其力量不低于怪兽的力量。
    一个英雄可以被选派多次。
    问最少需要多少天能打败所有的怪兽。

    思路:

    • 考虑(dp:dp[i])表示打败前(i)只怪兽最少需要多少天,显然(dp[i]=min{dp[j]+1})
    • (j)满足存在一个英雄,能从(j+1)打到(i),显然这个(j)的位置具有单调性。
    • 发现(dp)值也是单调不降的,那么我们就可以找一个最远的(j)进行转移,二分即可。
    • 二分的话,可以对英雄的耐力维护一个后缀最大值,即(maxv[s])表示耐力(geq s)的英雄中,最大的力量为多少;同时维护怪兽力量的区间最大值,这里(rmq)维护即可。两个判断一下就行。

    神志不清写了一年

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/13 23:47:28
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int n, m;
    int a[N];
    struct node{
        int s, p;   
        bool operator < (const node &A) const {
            return s < A.s;   
        }
    }b[N];
    int f[N][22];
    int lg[N];
    void init() {
        lg[2] = 1;
        for(int i = 3; i < N; i++) lg[i] = lg[i >> 1] + 1;   
    }
    int ask(int l, int r) {
        int k = lg[r - l + 1];
        return max(f[l][k], f[r - (1 << k) + 1][k]);   
    }
    int dp[N], maxv[N];
    bool chk(int l, int r) {
        int mx = ask(l, r);
        int i = lower_bound(b + 1, b + m + 1, node{r - l + 1, 0}) - b;
        return maxv[b[i].s] >= mx;
    }
    int get(int x) {
        int l = 1, r = x + 1, mid;
        while(l < r) {
            mid = (l + r) >> 1;
            if(chk(mid, x)) r = mid;
            else l = mid + 1;
        }   
        return r;
    }
    void run(){
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i], f[i][0] = a[i];
        for(int i = 1; i <= 20; i++) {
            for(int j = 1; j + (1 << (i - 1)) <= n; j++) {
                f[j][i] = max(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);
            }
        }
        cin >> m;
        for(int i = 1; i <= m; i++) cin >> b[i].p >> b[i].s;
        sort(b + 1, b + m + 1);
        b[m + 1].s = 0;
        for(int i = m; i >= 1; i--) {
            maxv[b[i].s] = max(maxv[b[i + 1].s], b[i].p);   
        }
        if(maxv[b[1].s] < ask(1, n)) return pt(-1);
        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            int p = get(i) - 1;
            dp[i] = dp[p] + 1;
        }
        cout << dp[n] << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        int T; cin >> T;
        while(T--) run();
    	return 0;
    }
    

    E. The Contest

    题意:
    给出三个集合,每个集合里面装了一些数,这些数的并集为(1)~(n)的排列。
    现在可以移动任意一个数从一个集合到另外一个集合。
    问最少的移动次数使得(1)集合中为一个前缀(1,cdots,k),然后(2)集合中(k+1,cdots,p)(3)集合中(p+1,cdots,n)。(可以有集合为空集)。

    思路:

    • 考虑枚举(1)集合中装的前缀的长度,然后将其余的所有数我们先移到(3)集合中,并且给这些数打上标记,表示删除这些数不消耗额外的次数。
    • 之后我们要操作一些数,使得(3)集合中的数为一个后缀。
    • 显然我们对(3)集合的操作是删掉前面的一些数,然后填补后面的空格。假设(3)集合中的数为(p)~(n),那么我们用(pre[i])表示(3)集合中原来有的数的前缀,(suf[i])表示后缀空格的数量。那么显然我们枚举(i,igeq p),求出(min{pre[i]-pre[p-1]+suf[i+1]})即可。
    • 显然(p)随着枚举(1)集合前缀个数时在不断增大,那么直接维护后缀(pre[i]+suf[i+1])的最小值即可。

    时间复杂度(O(n))。也可以(dp)来做,(dp[i][j])表示第(i)个数在第(j)个集合的最小操作次数。因为分布连续,直接分情况考虑即可。
    然而神志不清,想了好久都没想清楚

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/14 9:29:05
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    //#define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int k1, k2, k3, n;
    int a[N], b[N], c[N];
    int suf[N], pre[N], sum[N], Min[N];
    int f[N];
     
    void run(){
        n = k1 + k2 + k3;
        memset(f, 0, sizeof(f));
        for(int i = 1; i <= k1; i++) cin >> a[i];
        for(int i = 1; i <= k2; i++) cin >> b[i];
        for(int i = 1; i <= k3; i++) cin >> c[i];
        int tot = 0;
        int i = 1, j = 1;
        for(int i = 1; i <= k1; i++) f[a[i]] = 2;
        for(int i = 1; i <= k3; i++) f[c[i]] = 1;
        for(int i = 1; i <= n; i++) {
            pre[i] = pre[i - 1] + (f[i] == 1);
        }
        for(int i = n; i >= 1; i--) {
            suf[i] = suf[i + 1] + (f[i] == 0);
        }
        for(int i = n; i >= 0; i--) {
            if(i == n) Min[i] = pre[i];
            else Min[i] = min(Min[i + 1], pre[i] + suf[i + 1]);
        }
        for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (f[i] == 2);
        int ans = INF;
        for(int i = 0; i <= n; i++) {
            dbg(i, pre[i], suf[i], Min[i] - pre[i]);
            ans = min(ans, i - 2 * sum[i] + sum[n] - pre[i] + Min[i]);
        }
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> k1 >> k2 >> k3) run();
    	return 0;
    }
    

    F. Make Them Similar

    题意:
    给出(n,nleq 100)个数,现在定义两个数相似为其二进制(1)的个数相同。
    现在问能否找到一个数(x),使得这(n)个数都异或上(x),并且最终都相似。
    (a_ileq 2^{30}-1)

    思路:

    • 显然我们要从二进制的每一位来考虑,但是直接来考虑又显然不行。
    • 注意到二进制位不超过(30),那么可以考虑(meet in middle)的方法:即折半处理,预处理出一边,然后枚举这一边。
    • 预处理一边后随便用个(map)或哈希一下存储即可。

    感觉这个比前几个稍微还简单点?
    可能是因为我之前神志不清hhh

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/14 15:21:26
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 100 + 5;
     
    int n;
    int a[N];
     
    unordered_map<string, int> mp;
    string trans(int x) {
        string res = "";
        if(x > 9) {
            res += ((x / 10) + '0');
            res += ((x % 10) + '0');
        } else res += (x + '0');
        return res;
    }
    void run(){
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 0; i < 1 << 15; i++) {
            for(int k = 0; k <= 30; k++) {
                int ok = 1;
                for(int j = 1; j <= n; j++) {
                    int x = (a[j] >> 15) ^ i;        
                    if(__builtin_popcount(x) > k) ok = 0;
                }
                if(ok) {
                    string tmp = "";
                    for(int j = 1; j <= n; j++) {
                        int x = (a[j] >> 15) ^ i;
                        tmp += trans(k - __builtin_popcount(x));
                    }
                    if(mp.find(tmp) == mp.end())
                        mp[tmp] = i;
                }
            }
        }
        for(int i = 0; i < 1 << 15; i++) {
            string tmp = "";
            for(int j = 1; j <= n; j++) {
                int x = ((a[j] >> 15) << 15) ^ a[j];
                x ^= i;
                tmp += trans(__builtin_popcount(x));
            }
            if(mp.find(tmp) != mp.end()) {
                int ans = (mp[tmp] << 15) + i;
                cout << ans << '
    ';
                return;   
            }
        }
        cout << -1 << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n) run();
    	return 0;
    }
    
  • 相关阅读:
    如何手动封装 $ on off emit?
    Vue 实例身上的一些方法(二)
    Vue 实例身上的一些方法(一)
    Vue属性过滤
    Vue属性监听
    Vue实现简单的商品增减功能
    Vue 计算属性
    使用Vue实现一个简单地自定义拖拽功能
    数组的深拷贝与浅拷贝
    如何让html引用公共布局(多个html文件公用一个header.html和footer.html)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11861110.html
Copyright © 2020-2023  润新知