zoukankan      html  css  js  c++  java
  • Codeforces Round #668 (Div. 1)

    传送门

    A. Balanced Bitstring

    题意:
    给一个01串,其中某些位置为'?',即可以为0也可以为1。
    并且会给出一个 (k)(k) 是偶数,现在问是否可以使得所有长度为 (k) 的子串中都包含相等的0和1。

    思路:
    显然可以发现该串存在一个长度为 (k) 的循环节。
    也就是说每隔 (k) 个位置的数一定相等,根据这一点来做就好了。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/16 11:04:53
    #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, k;
        cin >> n >> k;
        string s;
        cin >> s;
        for (int i = 0; i < k; i++) {
            bool has_0 = false, has_1 = false;
            for (int j = i; j < n; j += k) {
                if (s[j] == '0') has_0 = true;
                if (s[j] == '1') has_1 = true;
            }
            if (has_0 && has_1) {
                cout << "NO" << '
    ';
                return;
            }
            if (has_0) {
                for (int j = i; j < n; j += k) {
                    s[j] = '0';
                }
            }
            if (has_1) {
                for (int j = i; j < n; j += k) {
                    s[j] = '1';
                }
            }
        }
     
        vector<int> cnt(2);
        for (int i = 0; i < k; i++) {
            if (s[i] == '0') ++cnt[0];
            else if (s[i] == '1') ++cnt[1];
        }
        if (cnt[0] <= k / 2 && cnt[1] <= k / 2) {
            cout << "YES" << '
    ';
        } else {
            cout << "NO" << '
    ';
        }
    }
    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. Tree Tag

    题意:
    给定一颗 (n) 个点的无根树,现在有两个人分别位于结点 (a)(b)。现在第一个人每次最多能跳 (da) 距离,第二个人最多能跳 (db) 距离。
    如果存在某一时刻两个人位于同一个点,那么第一个人就win;否则第二个人win。

    思路:
    题意就是第一个人要抓第二个人,第二个人就负责跑。
    我们可以分情况来做做:

    • 如果 (A) 上来就能抓住显然就没了;
    • (2cdot dageq L)(L) 为树的直径。这显然 (A) 只需要跳到树的重心,之后便可跳到任意一个位置;
    • 现在一定存在死角,假设 (B) 位于死角,(A) 之后一定会跳过来,假设 (A) 下一步就能抓住 (B) 了,此时又分情况:
      • (dbleq 2 * da),那 (B) 铁定跑不掉;
      • 否则 (B) 还是有机会跑掉的,这个较为显然,注意现在的情况存在一个前提:(L>da && db>2*da)

    就分上面几种情况来做,还是有点细节。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/07 09:29:10
    #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, a, b, da, db;
        cin >> n >> a >> b >> da >> db;
        --a, --b;
        vector<vector<int>> G(n);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            --u, --v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        vector<int> dep(n), up(n);
        int L = 0, rt = 0;
        function<void(int, int)> dfs = [&] (int u, int fa) {
            up[u] = fa;
            if (dep[u] > L) {
                L = dep[u];
                rt = u;
            }
            for (auto v : G[u]) if (v != fa) {
                dep[v] = dep[u] + 1;
                dfs(v, u);
            }
        };
        dfs(0, -1);
        dep[rt] = 0;
        int node = rt;
        dfs(rt, -1);
        int x = a, y = b;
        if (dep[a] < dep[b]) 
            swap(a, b);
        while (dep[a] > dep[b]) 
            a = up[a];
        while (a != b)
            a = up[a], b = up[b];
        int dis = dep[x] + dep[y] - 2 * dep[a];
        if (da >= dis || min(L, db) <= 2 * da) {
            cout << "Alice" << '
    ';
        } else {
            cout << "Bob" << '
    ';
        }
    }
    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;
    }
    

    C. Fixed Point Removal

    题意:
    给定一个序列 (a),现在可以执行若干次下面的操作:

    • (a_i=i),那么可以删除 (a_i),后面的元素往前移动。

    然后回答若干组询问,每组询问为一段区间,表示只能删除区间 ([l,r]) 中的数。
    对于每组询问回答最多能够执行多少次上述操作。

    思路:
    一个较为显然的想法是令 (a_i=i-a_i),那么每次能够删除一个为 (0) 的位置,后面的元素都减去 (1)
    如果没有询问的话那么就是一个贪心,我们每次删除最后面的那个 (0) 就行。
    但现在有询问就比较难搞,仔细思考其实可以注意到如果固定左端点,我们不断增加右端点的话就很好做,具体来说假设当前 ([l,r]) 的答案为 (x),之后右端点要增加 (1)。那么如果 (0leq a_{r+1}leq x)([l,r+1]) 的答案将变为 (x+1)。我们不用管是如何操作的,但是最后最优方法一定可以使得答案增加 (1)

    但是现在有很多个区间,左端点还会移动,这样不好判断。

    我们还是考虑从左往右移动右端点,用一个数组比如 (f[i]) 表示左端点为 (i) 时的答案。容易发现 (f[1]geq f[2]geqcdotsgeq f[r])。那么根据这一点,我们右端点移动时,会有一个前缀增加 (1),现在就很容易通过数据结构去维护了。
    现在只需将询问离线,在访问到询问区间右端点时统计答案即可。
    细节见代码:

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/16 15:46:25
    #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;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = (1 << 19);
     
    struct FT {
        int c[N];
        int lowbit(int x) {
            return x & -x;
        }
        void add(int x, int v) {
            for (++x; x < N; x += lowbit(x)) {
                c[x] += v;
            }
        }
        int query(int x) {
            int res = 0;
            for (++x; x; x -= lowbit(x)) {
                res += c[x];
            }
            return res;
        }
        int find(int x) {
            int p = 0;
            for (int i = 18; i >= 0; i--) {
                if (query(p | (1 << i)) >= x) {
                    p |= (1 << i);
                }
            }
            return p - 1;
        }
    } bit;
     
    void run() {
        int n, q;
        cin >> n >> q;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            --a[i];
            a[i] = i - a[i];
        }
     
        vector<vector<pii>> Q(n);
        for (int i = 1; i <= q; i++) {
            int x, y;
            cin >> x >> y;
            int l = x, r = n - y - 1;
            Q[r].emplace_back(l, i);
        }
        vector<int> ans(q + 1);
        for (int r = 0; r < n; r++) {
            if (a[r] >= 0) {
                int L = 0, R = r + 1, mid;
                while (L < R) {
                    mid = (L + R) >> 1;
                    if (bit.query(mid) >= a[r]) {
                        L = mid + 1;
                    } else {
                        R = mid;
                    }
                }
                // dbg(r, L);
                bit.add(0, 1), bit.add(L, -1);
            }
     
            for (auto& it : Q[r]) {
                int l = it.fi, id = it.se;
                ans[id] = bit.query(l);
            }
        }
        for (int i = 1; i <= q; i++) {
            cout << ans[i] << '
    ';
        }
    }
    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;
    }
    

    D. Game of Pairs

    题意:
    首先会给定一个 (n),然后可以选择先手或者后手:

    • 如果选择先手,将 (1,2,cdots,2n) 两两分组,后手此时只能从每组里面选择一个,如果选出来的数的和是 (2n) 的倍数就输了,否则就赢;
    • 如果选择后手,那么会给出来一个类似于上面的分组,现在你要选出一些数,如果这些数的和为 (2n) 的倍数那么就赢了,否则就输。

    现在就问怎么操作能够必胜。

    思路:
    如果 (n) 为偶数的话,那么类似于 ((1,n+1),(2,n+2),cdots,(n,2n)) 这样分组能够必胜。
    原因在于所有组中的两个数在模 (n) 意义下就是相等的。那么后者必然选出来的数满足 (displaystyle 1+2+cdots+n-1equiv frac{ncdot(n-1)}{2}(mod n))
    分式很难看,令 (n=2m),就有 (mcdot(2m-1)(mod 2m))。因为 (2m-1) 为奇数,那么式子显然不为 (0),也就是说不整除 (n),显然也不整除 (2n)

    如果 (n) 为奇数的话,需要下面的观察:

    • 所有数的和为 (ncdot(2n+1)),其在模 (2n) 意义下为(n)。那么如果我选出来的数在模 (n) 意义下为 (0),就能找到答案。

    因为此时如果 (\% 2n)(0),就是答案;如果为 (n),我全部选另外的数,那就是答案。

    还有另外一个观察:

    • (displaystyle 1+2+cdots+n-1equiv frac{ncdot(n-1)}{2}),此时 (n) 为奇数,那么一定是 (n) 的倍数。

    所以现在我们就选出一些在模 (n) 意义下两两不同的数即可。
    这个是能够选出来的,我们连边 (i ightarrow i+n),以及分组中的数互相连边,那么最终一定会形成若干个长度为偶数的环。之后对每个环奇偶染色即可。

    Code
    // Author : heyuhhh
    // Created Time : 2020/09/16 18:33:32
    #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;
        cin >> n;
        if (n % 2 == 0) {
            cout << "First" << '
    ';
            for (int i = 0; i < 2 * n; i++) {
                if (i) cout << ' ';
                cout << i % n + 1;
            }
            cout << endl << endl;
            int x;
            cin >> x;
        } else {
            cout << "Second" << endl << endl;
            vector<vector<int>> has(n);
            for (int i = 0; i < 2 * n; i++) {
                int bel;
                cin >> bel;
                --bel;
                has[bel].emplace_back(i);
            }
            vector<vector<int>> G(2 * n);
            for (int i = 0; i < n; i++) {
                G[i].emplace_back(i + n);
                G[i + n].emplace_back(i);
            }
            for (int i = 0; i < n; i++) {
                G[has[i][0]].emplace_back(has[i][1]);
                G[has[i][1]].emplace_back(has[i][0]);
            }
            vector<int> col(2 * n, -1);
            vector<int> zeros, ones;
            int res = 0;
            function<void(int, int)> go = [&] (int u, int c) {
                col[u] = c;
                if (c == 0) {
                    res = (res + u + 1) % (2 * n);
                    zeros.emplace_back(u);
                } else {
                    ones.emplace_back(u);
                }
                for (auto& v : G[u]) {
                    assert(col[v] != col[u]);
                    if (col[v] == -1) {
                        go(v, c ^ 1);
                    }
                }
            };
            for (int i = 0; i < 2 * n; i++) {
                if (col[i] == -1) {
                    go(i, 0);
                }
            }
            if (res == 0) {
                for (int i = 0; i < sz(zeros); i++) {
                    if (i) cout << ' ';
                    cout << zeros[i] + 1;
                }
            } else {
                for (int i = 0; i < sz(ones); i++) {
                    if (i) cout << ' ';
                    cout << ones[i] + 1;
                }
            }
            cout << endl << endl;
            int x;
            cin >> x;
        }
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    
  • 相关阅读:
    CodeForces Round #288 Div.2
    POJ 3660 Cow Contest【传递闭包】
    ZOJ 3321 Circle【并查集】
    CF 286(div 2) B Mr. Kitayuta's Colorful Graph【传递闭包】
    CF 287(div 2) B Amr and Pins
    HDU 2122 Ice_cream’s world III【最小生成树】
    HDU 1233 还是畅通工程【最小生成树】
    奶牛接力 矩阵乘法
    家谱 并差集
    昂贵的聘礼 最短路 dijkstra
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13788405.html
Copyright © 2011-2022 走看看