zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 002 DEF

    AGC002

    D - Stamp Rally

    多次询问,整体二分。具体一些,当前二分的区间为 (l,r),先设定答案为 (mid),判断是否可行,可行的往 ([l,mid]) 递归,否则走 ([mid + 1, r])。关键在于如何快速判定是否可行。

    用并查集维护连通块的大小,一种办法使用可回退并查集。还有一种是按照 (bfs) 顺序处理区间(按层处理)。这样只要在每层开头暴力清空,然后按照顺序连

    #include <bits/stdc++.h>
    using namespace std;
    void read (int &x) {
        char ch = getchar(); x = 0; while (!isdigit(ch)) ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    } const int N = 1e5 + 5;
    int n, m, q, res[N];
    struct query { int x, y, z; } a[N];
    struct edge { int x, y; } e[N];
    int fa[N], sz[N];
    int find (int x) { return fa[x] == x ? x : fa[x] = find (fa[x]); }
    void merge (int x, int y) {
        int fx = find (x), fy = find (y);
        if (sz[fx] > sz[fy]) swap (fx, fy);
        if (fx ^ fy) fa[fx] = fy, sz[fy] += sz[fx];
    }
    int cnt, ll[N << 2], rr[N << 2], tag[N << 2];
    vector<int> g[N << 2];
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    void build (int p, int l, int r) {
        ll[p] = l, rr[p] = r, tag[p] = 1;
        if (l == r) return; int mid (l + r >> 1);
        build (ls, l, mid), build (rs, mid + 1, r);
    }
    void solve () {
        for (int p = 1; p <= (n << 2); ++p) {
            if (!tag[p]) continue;
            // printf ("%d %d
    ", ll[p], rr[p]);
            if (ll[p] == 1) {
                for (int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
            }
            if (ll[p] == rr[p]) {
                merge (e[ll[p]].x, e[ll[p]].y);
                for (int i : g[p]) res[i] = ll[p]; continue;
            }
            int mid (ll[p] + rr[p] >> 1);
            for (int i = ll[p]; i <= mid; ++i) merge (e[i].x, e[i].y);
            for (int i : g[p]) {
                int x = a[i].x, y = a[i].y, z = a[i].z;
                x = find (x), y = find (y);
                int s = (x == y) ? sz[x] : sz[x] + sz[y];
                // printf ("%d %d %d
    ", i, s, z);
                s >= z ? g[ls].push_back (i) : g[rs].push_back (i);
            }
            for (int i = mid + 1; i <= rr[p]; ++i) merge (e[i].x, e[i].y);
        }
    }
    signed main() {
        read (n), read (m);
        for (int i = 1; i <= m; ++i) read (e[i].x), read (e[i].y);
        read (q);
        for (int i = 1; i <= q; ++i)
            read (a[i].x), read (a[i].y), read (a[i].z);
        for (int i = 1; i <= q; ++i) g[1].push_back (i);
        build (1, 1, m); solve ();
        for (int i = 1; i <= q; ++i) printf ("%d
    ", res[i]);
        return 0;
    }
    

    E - Candy Piles

    uxC5ND.png

    uxCT9H.png

    剽三张图助于理解。把所有石堆排序扔到坐标轴上后事情就很明显了。两种操作分别代表向上走一步和向右走一步。最外围一圈的胜负状态确定。

    可以发现,先手可以走到任意的 ((x,y),|x-y|leq1),后手可以控制 (|x-y|leq1),所以只要判断是否存在这样的 ((x,y)) 让先手胜,不胜则败。

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    void read (int &x) {
        char ch = getchar(); x = 0; while (!isdigit(ch)) ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    } const int N = 1e5 + 5;
    int n, tag, a[N];
    void work () {
        for (int i = 1; i <= n; ++i) {
            int j = i + 1;
            while (a[i] == a[j] && j <= n) ++j; --j;
            int l = i, r = j;
            if ((r - a[i]) & 1) {
                if (l <= a[i] - 1 && a[i] - 1 <= r) { tag = 1; break; }
                if (l <= a[i] + 1 && a[i] + 1 <= r) { tag = 1; break; }
            } i = j;
            l = a[i + 1] + 1, r = a[i];
            if (((r - i) & 1)) {
                if (l <= i - 1 && i - 1 <= r) { tag = 1; break; }
                if (l <= i + 1 && i + 1 <= r) { tag = 1; break; }
            }
        }
    }
    signed main() {
        read (n);
        for (int i = 1; i <= n; ++i) read (a[i]);
        sort (a + 1, a + n + 1), reverse (a + 1, a + n + 1);
        work ();
        puts (tag ? "First" : "Second");
        return 0;
    }
    

    F - Leftmost Ball

    因为每种颜色的求会有一个白色,所以可以重新把球分类为白球和其他颜色,这两种球相对独立

    这就是状态了:(f_{i,j}) 表示当前填了 (i) 个白球,(j) 类其他颜色的球的方案数 (其他颜色都是一下全部填完)

    转移依据也比较奇特:按照当前空位最左边填什么转移。这样可以保证白球的合法性

    如果填白的直接转,否则乘上一个组合数。当然其他颜色种类不能大于白球数量。组合数具体是什么不难想,就不写了(懒)

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    void read (int &x) {
        char ch = getchar(); x = 0; while (!isdigit(ch)) ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    } const int N = 2010, mod = 1e9 + 7;
    int n, k, f[N][N], pw[N * N], in[N * N];
    int qpow (int x, int y) {
        int t = 1;
        while (y) {
            if (y & 1) t = t * x % mod;
            x = x * x % mod, y >>= 1;
        } return t;
    }
    int C (int x, int y) {
        // if (x < y) return 0;
        return pw[x] * in[y] % mod * in[x - y] % mod;
    }
    signed main() {
        read (n), read (k); f[0][0] = pw[0] = 1;
        for (int i = 1; i <= n * k; ++i) pw[i] = pw[i - 1] * i % mod;
        in[n * k] = qpow (pw[n * k], mod - 2);
        for (int i = n * k; i >= 1; --i) in[i - 1] = in[i] * i % mod;
        if (k == 1) return puts ("1"), 0;
        for (int i = 1; i <= n; ++i)
            for (int j = 0; j <= i; ++j) {
                f[i][j] = f[i - 1][j];
                if (j) (f[i][j] += f[i][j - 1] * (n - j + 1) % mod * C (n * k - i - (j - 1) * (k - 1) - 1, k - 2)) %= mod;
            }
        return printf ("%lld
    ", f[n][n]), 0;
    }
    
  • 相关阅读:
    liunx 解压与压缩
    缓存设计与优化
    易混乱javascript知识点简要记录
    初识RedisCluster集群
    Redis Sentinel(哨兵模式)
    JavaScript作用域简单记录
    JavaScript引用类型简单记录
    redis主从复制初识
    javascript基础知识点
    持久化的一些问题
  • 原文地址:https://www.cnblogs.com/whx666/p/14184791.html
Copyright © 2011-2022 走看看