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

    Codeforces Round #601 (Div. 1)

    A

    容易发现最小的差肯定是 (1),即有一些块包含 (x) 个,一些块有 (x+1) 个。关键在于保证连通。只要按照“蛇形”拓展即可:一行一行走,第一行从左往右,第二行从右往左,第三行...

    #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 = 105;
    int n, m, k, p[100], vis[N][N]; char a[N][N], b[N][N];
    signed main() {
        int T; read (T); int m = 0;
        for (int i = '0'; i <= '9'; ++i) p[++m] = i;
        for (int i = 'a'; i <= 'z'; ++i) p[++m] = i;
        for (int i = 'A'; i <= 'Z'; ++i) p[++m] = i;
        while (T--) {
            read (n), read (m), read (k);
            for (int i = 1; i <= n; ++i) scanf ("%s", a[i] + 1);
            int cnt = 0;
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= m; ++j) cnt += a[i][j] == 'R', vis[i][j] = 0;
            int num = cnt / k, s = cnt - k * num;
            int x = 1, y = 1, now = 0, f = 1, id = 1;
            while (id <= s) {
                // printf ("%d %d %d
    ", x, y, id);
                now += a[x][y] == 'R', b[x][y] = p[id], vis[x][y] = 1;
                if (y + f <= m && y + f >= 1) y += f;
                else ++x, f = -f; if (x > n) break;
                if (now == num + 1) now = 0, ++id;
            }
            while (id <= k) {
                // printf ("%d %d %d
    ", x, y, id);
                now += a[x][y] == 'R', b[x][y] = p[id], vis[x][y] = 1;
                if (y + f <= m && y + f >= 1) y += f;
                else ++x, f = -f; if (x > n) break;
                if (now == num) now = 0, ++id;
            }
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= m; ++j) if (!vis[i][j]) b[i][j] = p[id - 1];
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) putchar (b[i][j]); putchar ('
    ');
            }
        }
        return 0;
    }
    
    

    B

    对于 easy version,枚举约数 (p),由于每个位置不超过 (1),一定是连续 (p)(1) 拼在一起。然后就成了“数轴上有一些村庄,建车站使距离和最短”的问题

    对于 hard,首先可以发现 (p) 只需考虑质数,否则不会更优。为了简化问题,设 (b_i=sumlimits_{j=1}^{i}a_i)。把 (i) 移到 (i+1) 就是 (b_i)(1),移到 (i-1) 就是 (b_{i-1})(1)。其实就是可以任选一个 (iin[1,n-1]) 加一减一。(res=sum min(b_i\%p,p-b_i\%p))

    质因数没几个((leq12)),所以很快

    #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 = 1e6 + 5;
    int n, a[N], s[N], p[N], in[N];
    signed main() {
        read (n);
        for (int i = 1; i <= n; ++i) read (a[i]);
        for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
        if (s[n] == 1) return puts ("-1"), 0;
        int res = 5e18, sum = s[n];
        for (int i = 2; i * i <= s[n]; ++i) {
            if (!in[i]) {
                if (sum % i == 0) {
                    while (sum % i == 0) sum /= i; int tmp = 0;
                    for (int j = 1; j <= n; ++j) tmp += min (s[j] % i, i - s[j] % i);
                    res = min (res, tmp);
                }
                for (int j = i; j * j <= s[n]; j += i) in[j] = 1;
            }
        }
        if (sum > 1) {
            int tmp = 0;
            for (int j = 1; j <= n; ++j) tmp += min (s[j] % sum, sum - s[j] % sum);
            res = min (res, tmp);
        }
        return printf ("%lld
    ", res), 0;
    }
    
    

    C

    先通过 (1,2) 两点确定的直线把点分成 (A,B) 两部分,这一步可以通过 (n-2)(2) 类询问 ((1,2,x)) 完成

    然后对于每个点进行 (1) 类查询 ((1,2,x)),由此可以得出每个点到直线 (1,2) 的距离。记最远点为 (u),再通过 (2) 类询问 ((1,u,x)) 可以把 (A) 中的点再次分为 (A_1,A_2) 两部分 ((B) 同)

    然后对于 (A_1,A_2) 点的顺序分别按照点到线的距离降序、升序排列。需要注意的是最远点可能有两个

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 1024;
    int n, h[N]; vector<int> a, b, res;
    void flush () { putchar ('
    '); fflush (stdout); }
    vector<pair<int, int> > l, r;
    #define fi first
    #define se second
    #define pb push_back
    signed main() {
        cin >> n;
        for (int i = 3, x; i <= n; ++i) {
            printf ("2 1 2 %lld", i);
            flush (); cin >> x;
            x == -1 ? a.pb (i) : b.pb (i);
        }
        int u = 0, d = 0, v = 0;
        for (int i : a) {
            printf ("1 1 2 %lld", i);
            flush (); int x; cin >> x; h[i] = x;
            if (x > d) d = x, u = i, v = 0;
            else if (x == d) v = i;
        }
        for (int i : a) {
            if (i == u || i == v) continue;
            printf ("2 1 %lld %lld", u, i);
            flush (); int x; cin >> x;
            if (x == 1) r.pb ({h[i], i});
            else l.pb ({h[i], i});
        }
        res.pb (1);
        sort (l.begin(), l.end());
        for (auto i : l) res.pb (i.se);
        if (!v && u) res.pb (u);
        if (u && v) {
            printf ("2 1 %lld %lld", u, v);
            flush (); int x; cin >> x;
            if (x < 0) swap (u, v);
            res.pb (u), res.pb (v);
        }
        sort (r.begin(), r.end());
        reverse (r.begin(), r.end());
        for (auto i : r) res.pb (i.se);
        res.pb (2);
        ////////////////////////////
        u = 0, d = 0, v = 0; l.clear(), r.clear();
        for (int i : b) {
            printf ("1 1 2 %lld", i);
            flush (); int x; cin >> x; h[i] = x;
            if (x > d) d = x, u = i, v = 0;
            else if (x == d) v = i;
        }
        for (int i : b) {
            if (i == u || i == v) continue;
            printf ("2 1 %lld %lld", u, i);
            flush (); int x; cin >> x;
            if (x == 1) l.pb ({h[i], i});
            else r.pb ({h[i], i});
        }
        sort (r.begin(), r.end());
        for (auto i : r) res.pb (i.se);
        if (!v && u) res.pb (u);
        if (u && v){
            printf ("2 1 %lld %lld", u, v);
            flush (); int x; cin >> x;
            if (x < 0) swap (u, v);
            res.pb (u), res.pb (v);
        }
        sort (l.begin(), l.end());
        reverse (l.begin(), l.end());
        for (auto i : l) res.pb (i.se);
        printf ("0 ");
        for (int i : res) printf ("%lld ", i);
    }
    
    

    D

    操作 (x),此时以 (x) 为根,(y) 被修改的概率和 (y)(x) 的哪个儿子的子树中有关,只要 (r) 不选在这棵子树中 (y) 就被修改。容易发现朴素算法的复杂度是操作节点的度数之和

    1、对于度数分类处理,(gesqrt{n}) 的打标记,查询的时候再算,(leqsqrt{n}) 的直接暴力修改,根据实现方式不同可以做到 (O(nsqrt{n})——O(nsqrt{n}log{n}))

    2、轻重链剖分,对于 (x) 的重儿子的子树和外子树暴力修改,轻儿子不管,查询的时候跳重链累计答案(两条重链相接处)。每次暴力修改 (2) 个区间,(O(log{n}))。每次查询的时候重链最多 (log n) 条,概率 (O(1)) 计算,复杂度也为 (O(log n))。总复杂度 (O(nlog n))

    #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 = 150010, M = N << 1, mod = 998244353;
    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 n, q, cnt, inv, h[N], to[M], nxt[M];
    void add (int u, int v) {
        to[++cnt] = v, nxt[cnt] = h[u], h[u] = cnt;
    }
    #define up(x, y) ((x += y) >= mod && (x -= mod))
    struct tree {
        int c[N];
        void add (int x, int v) {
            for (++x; x <= n + 1; x += (x & -x)) up (c[x], v);
        }
        int ask (int x) {
            int s = 0; for (++x; x; x -= (x & -x)) up (s, c[x]); return s;
        }
        void update (int l, int r, int v) { add (l, v), add (r + 1, mod - v); }
    } t;
    struct solve {
        int cnt, d[N], son[N], sz[N], dfn[N], fa[N], tp[N], ed[N], num[N];
        void dfs (int u) {
            sz[u] = 1;
            for (int i = h[u], v; i; i = nxt[i]) {
                if ((v = to[i]) == fa[u]) continue;
                fa[v] = u, d[v] = d[u] + 1, dfs (v), sz[u] += sz[v];
                if (sz[v] > sz[son[u]]) son[u] = v;
            }
        }
        void dfs (int u, int topp) {
            tp[u] = topp, dfn[u] = ++cnt;
            if (son[u]) dfs (son[u], topp);
            for (int i = h[u], v; i; i = nxt[i])
                if (!dfn[v = to[i]]) dfs (v, v); ed[u] = cnt;
        }
        void prework () { dfs (1); dfs (1, 1); }
        void modify (int x, int c) {
            int l = 1, r = dfn[x] - 1, k = c * inv % mod * sz[x] % mod;
            if (l <= r) t.update (l, r, k);
            l = ed[x] + 1, r = n;
            if (l <= r) t.update (l, r, k);
            if (son[x]) {
                int y = son[x];
                l = dfn[y], r = ed[y], k = c * inv % mod * (n - sz[y]) % mod;
                if (l <= r) t.update (l, r, k);
            }
            up (num[x], c);
        }
        int ask (int x) {
            int res = num[x]; up (res, t.ask (dfn[x]));
            while (x) {
                int a = tp[x], b = fa[tp[x]]; x = b;
                (res += num[b] * inv % mod * (n - sz[a])) %= mod;
            }
            return res;
        }
    } qwq;
    signed main() {
        read (n), read (q); inv = qpow (n, mod - 2);
        for (int i = 1, u, v; i < n; ++i)
            read (u), read (v), add (u, v), add (v, u);
        qwq.prework (); int o, x, c;
        for (int i = 1; i <= q; ++i) {
            read (o), read (x);
            if (o == 1) read (c), qwq.modify (x, c);
            else printf ("%lld
    ", qwq.ask (x));
        }
        return 0;
    }
    
    

    E

    如果没有限制,(res=prod s_i)(s_i)(i) 节点的度数。

    一个限制意味着什么?提取出 (path(x,a_x)) 这条链,有三种限制

    1、(x) 的第一条删除的边固定。

    2、(a_x) 的最后一条删除边固定。

    3、链上的边删除有依赖关系(可传递)。即删除完一条边后,和公共点相连的边中必须立刻删除链上的下一条。

    注意到有依赖关系的边都有一个公共点。

    把和某个点相邻的边提出来,把这些边看成节点,每个依赖关系连一条有向边,构成一张“新图”(下面提到“新链”是“新图”中的链,“链”指原图的链)

    可以找到一些无解的情况:

    1、某个 (x)(a) 中出现不止一次

    2、和某条边有直接依赖关系的边不止一条或依赖关系成环(In other words,“新图”中有节点出度或入度 (ge 2) 或 "新图"中有环)

    3、某个点的第一条边和最后一条边固定且在同一条“新链”上,但还有其他“新链”存在

    4、如果链 (path(x,a_x)) 的长度之和 (ge 2n-1),一定无解,因为每删除一条边 (i) 节点和数字 (i) 的距离之和 (+2)。所以可以暴力判断无解而保证复杂度。

    如果有解,答案就是 (prod c_i!)(c_i) 为“新链”数量。

    语文水平太低,说的很模糊,但又懒得画图,不如↓

    #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 = 5e5 + 5, mod = 1e9 + 7;
    int n; vector<int> g[N];
    #define int long long
    void fail () { puts ("0"); exit (0); }
    int sum, d[N], fa[N], nxt[N], pre[N], vis[N];
    void dfs (int u, int la) {
        d[u] = d[la] + 1, fa[u] = la;
        for (int v : g[u]) if (v != la) dfs (v, u);
    }
    vector<int> vx, vy;
    #define pb push_back
    void lca (int x, int y) {
        vx.clear(), vy.clear(); vx.pb (n + 1), vy.pb (n + 2);
        while (d[x] > d[y]) ++sum, vx.pb (x), x = fa[x];
        while (d[x] < d[y]) ++sum, vy.pb (y), y = fa[y];
        while (x != y) sum += 2, vx.pb (x), vy.pb (y), x = fa[x], y = fa[y];
        vx.pb (x);
    }
    struct e { int x, y; } ; vector<e> a[N];
    void work (int x, int y) {
        lca (x, y); if (sum > 2 * n - 2) fail ();
        vx.insert (vx.end(), vy.rbegin(), vy.rend()); int sx = (int)vx.size();
        for (int i = 1; i + 1 < sx; ++i) a[vx[i]].pb ({vx[i - 1], vx[i + 1]});
    }
    signed main() {
        read (n);
        for (int i = 1, u, v; i < n; ++i)
            read (u), read (v), g[u].pb (v), g[v].pb (u);
        for (int i = 1; i <= n; ++i)
            g[i].pb (n + 1), g[i].pb (n + 2);
        if (n == 1) return puts ("1"), 0;
        dfs (1, 1); int res = 1;
        for (int i = 1, x; i <= n; ++i) { read (x); if (x) work (i, x); }
        for (int i = 1; i <= n; ++i) {
            for (e p : a[i]) {
                int x = p.x, y = p.y;
                if (nxt[x] && nxt[x] != y) fail ();
                if (pre[y] && pre[y] != x) fail ();
                nxt[x] = y, pre[y] = x;
            }
            for (int x : g[i]) if (!vis[x]) {
                vis[x] = 1; int now = nxt[x];
                while (now) {
                    if (now == x) fail ();
                    if (vis[now]) break; vis[now] = 1, now = nxt[now];
                }
            }
            if (nxt[n + 1]) {
                int now = n + 1, c = 1;
                while (now) {
                    if (now == n + 2) break; ++c, now = nxt[now];
                }
                if (now == n + 2 && c < g[i].size()) fail ();
            }
            int num = 0;
            for (int x : g[i]) num += (x <= n && !pre[x]);
            if (pre[n + 2]) --num;
            for (int j = 1; j <= num; ++j) res = res * j % mod;
            for (int x : g[i]) nxt[x] = pre[x] = vis[x] = 0;
        }
        printf ("%lld
    ", res);
    }
    
    
  • 相关阅读:
    Linux系统常用目录操作函数 分类: B3_LINUX 20130218 16:44 486人阅读 评论(0) 收藏
    查找数组中最大的2个数 分类: B10_计算机基础 20130211 19:52 1041人阅读 评论(1) 收藏
    C语言程序的内存分配方式 分类: H_HISTORY 20130211 10:18 876人阅读 评论(3) 收藏
    sqlplus环境配置(login.sql) 分类: H2_ORACLE 20130517 09:24 1382人阅读 评论(0) 收藏
    GoldenGate系统二:快速搭建三方单向通信GoldenGate环境 分类: H2_ORACLE 20130516 10:54 827人阅读 评论(0) 收藏
    C语言声明数组变量时,在什么情况下,可不指定数组大小 分类: H_HISTORY 20130211 11:03 694人阅读 评论(0) 收藏
    【转载】linux中误删除oracle数据文件的恢复操作 分类: H2_ORACLE 20130614 12:07 353人阅读 评论(0) 收藏
    使用C语言读取properties文件V1.0 分类: H_HISTORY 20130226 12:37 946人阅读 评论(0) 收藏
    syslog()的基本用法 20130218 22:59 372人阅读 评论(0) 收藏
    使用异或加密数据 20130209 22:24 1043人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/whx666/p/601-div1.html
Copyright © 2011-2022 走看看