zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 006 BCDEFF

    AGC006

    B&D Median Pyramid Easy&Hard

    B和D关键步骤差不多,放一起了

    假设已知底部的元素,如何判定顶部的数是否 (ge x)

    (<x) 的数赋为 (0) ,反之为 (1),因为只要判断是否在范围内,和具体值无关

    结论:如果有两个 (1) 相邻,则这两竖全都是 (1)(0) 也是一样

    看一下离中点最近的 "0对" 和 “1对”,如果 “1对” 更近,顶端的数 (ge x),否则 (<x)

    如果不存在 "0对" 和 “1对”,(0,1) 间隔存在,特判一下

    对于D题,二分答案 (x),判断答案是否 (ge x)

    对于B题,要构造出底端的数组,判定结果 (ge x)(<x+1) ,可以想到最中间三个元素为 (x,x-1,x+1),其他的随意,如果 (x) 是最小值或最大值不存在解

    B:

    #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 = 2e5 + 5;
    int n, x, a[N];
    signed main() {
        read (n), read (x);
        if (x == 1 || x == 2 * n - 1) return puts ("No"), 0;
        puts ("Yes");
        for (int i = 1, j = 1; i <= 2 * n - 1; ++i) {
            if (i == n - 1) { printf ("%d
    ", x - 1); continue; }
            if (i == n + 1) { printf ("%d
    ", x + 1); continue; }
            if (i == n) { printf ("%d
    ", x); continue; }
            if (j == x - 1) j = x + 2; printf ("%d
    ", j), ++j;
        }
        return 0;
    }
    

    D

    #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();
    }
    int n, l, r, mid, ans, a[200010];
    bool check () {  
        for (int i = 0; i < n; ++i) {
        	if ((a[n-i] < mid and a[n-i-1] < mid) or (a[n+i] < mid and a[n+i+1] < mid))  
        	  return false;
        	if ((a[n-i] >= mid and a[n-i-1] >= mid) or (a[n+i] >= mid and a[n+i+1] >= mid))
        	  return true;
    	}
    	return a[n*2-1] >= mid;
    }
    signed main() {
    	read (n);
    	for (int i = 1; i <= (n << 1) - 1; ++i)  read (a[i]);
    	l = 1, r = (n << 1) - 1;
    	while (l <= r) {
    		mid = l + r >> 1;
    		if (check())  ans = mid, l = mid + 1;
    		else r = mid - 1;
    	}
    	printf ("%d
    ", ans);
    	return 0;
    }
    

    C - Rabbit Exercise

    (x) 操作一次后,(x) 的期望位置 (f_x=frac{1}{2}((2f_{x-1}-f_x)+(2f_{x+1}-f_x))=f_{x+1}+f_{x-1}-f_x)

    进行差分,(g_i=f_i-f_{i-1}),执行一次操作 (x) 相当于 (swap(g_x,g_{x+1}))

    先处理出一轮操作后的位置变化,然后倍增算出最后的位置变化,按照差值推一遍

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    void read (int &x) {
        char ch = getchar(); int f = 0; x = 0;
        while (!isdigit(ch)) { if (ch == '-') f = 1; ch = getchar(); }
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar(); if (f) x = -x;
    } const int N = 1e5 + 5;
    int n, m, k, a[N], p[N], d[N], now[N], t[N];
    void change (int *a, int *b) {
        for (int i = 2; i <= n; ++i) t[i] = a[b[i]];
        memcpy (a, t, sizeof (t));
    }
    signed main() {
        read (n);
        for (int i = 2; i <= n; ++i) p[i] = now[i] = i;
        for (int i = 1; i <= n; ++i) read (a[i]);
        for (int i = 2; i <= n; ++i) d[i] = a[i] - a[i - 1];
        read (m), read (k);
        for (int i = 1, x; i <= m; ++i)
            read (x), swap (p[x], p[x + 1]);
        while (k) {
            if (k & 1) change (now, p);
            change (p, p), k >>= 1;
        }
        for (int i = 1, res = a[1]; i <= n; ++i)
            printf ("%lld
    ", res), res += d[now[i + 1]];
        return 0;
    }
    

    E - Rotate 3x3

    首先,一些明显的无解:

    1、某一列内的三个数不应该在同一列中

    2、这一列应该在的列和当前在的列奇偶性不同(隔一个交换不改变奇偶性)

    把奇偶列分开,然后发现:可以仅翻转任意两个奇数列的上下顺序而不改变其他列的上下、左右顺序,偶数列同理

    具体做法是:假设要翻转两个奇数列 (x,y),先把 (x) 若干此翻转到 (y) 的旁边(隔一列),对中间一列操作,再把 (x) 弄回去。

    先统计一下奇偶列分别需要上下翻转的次数,但在排序偶数列的过程中对奇数列有影响,还要减去排序用的交换次数。如果奇偶剩下的都是个偶数(可以为负)就可以

    求排序过程中交换次数的奇偶性方法就很多了...

    #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, s[2], c[3][N], p[N], a[N];
    #define fail return puts ("No"), 0
    signed main() {
        read (n);
        for (int i = 0; i < 3; ++i)
            for (int j = 1; j <= n; ++j) read (c[i][j]);
        for (int i = 1; i <= n; ++i) {
            int tag = 0, id = (c[1][i] + 2) / 3;
            if (c[0][i] % 3 == 0) tag = 1, s[i & 1] ^= 1, swap (c[0][i], c[2][i]);
            if ((i & 1) != (id & 1)) fail;
            for (int j = 0; j < 3; ++j)
                if (c[j][i] != 3 * id - 3 + j + 1) fail;
            a[i] = id, p[id] = i;
        }
        for (int i = 1; i <= n; ++i) {
            if (a[i] == i) continue;
            p[a[i]] = p[i], swap (a[i], a[p[i]]);
            s[i & 1 ^ 1] ^= 1;
        }
        if (s[0] || s[1]) fail;
        return puts ("Yes"), 0;
    }
    

    F - Blackout

    先说结论:对每一个连通块三染色,即把 (R) 点连向的点染成 (G)(G) 连向 (B)(B) 连向 (R),如果可以成功染色:

    1、三种颜色都有,边的数量是 (cnt(R)*cnt(G)+cnt(G)*cnt(B)+cnt(B)*cnt(R))

    2、没有三种颜色,不能连新边,就是原来边的数量

    如果不能成功染色,最后会变成一张完全图

    为什么是对的?可以成功染色且没有三种颜色的情况显然正确,另外两种情况说一下大致做法,具体的要自己举例实践感受一下

    可以染色且三种颜色都有:把连通块每三层划为一段,先考虑每一段内有那些边可以连,然后和相邻的段进行合并,看一看哪些边可以连。

    如果不能染色,存在一个长度不是 (3) 的倍数的环,这样的环肯定可以形成完全图,然后从环出发向外拓展点,所有边都是可以连上的

    #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, M = N << 1;
    int n, m, res, tag, s, cc, co[N], c[3];
    int cnt, k[M], to[M], h[M], nxt[M];
    void add (int u, int v) {
        to[++cnt] = v, k[cnt] = 1, nxt[cnt] = h[u], h[u] = cnt;
        to[++cnt] = u, k[cnt] = -1, nxt[cnt] = h[v], h[v] = cnt;
    }
    int f (int x, int k) {
        x += k; if (x == -1) x = 2; if (x == 3) x = 0; return x;
    }
    void dfs (int u) {
        ++c[co[u]], ++s;
        for (int i = h[u], v; i; i = nxt[i]) {
            cc += k[i] == 1;
            if (co[v = to[i]] < 0) co[v] = f (co[u], k[i]), dfs (v);
            else if (co[v] != f (co[u], k[i])) tag = 0;
        }
    }
    signed main() {
        read (n), read (m);
        for (int i = 1, u, v; i <= m; ++i)
            read (u), read (v), add (u, v);
        memset (co, -1, sizeof (co));
        for (int i = 1; i <= n; ++i) {
            if (co[i] >= 0) continue;
            c[0] = c[1] = c[2] = s = cc = 0; tag = 1; co[i] = 0, dfs (i);
            if (!tag) res += s * s;
            else if (c[0] && c[1] && c[2]) res += c[0] * c[1] + c[1] * c[2] + c[2] * c[0];
            else res += cc;
        }
        return printf ("%lld
    ", res), 0;
    }
    
  • 相关阅读:
    SQL语句熟悉
    CSS3 attribute
    轮播器
    PHP 邮箱操作的Action
    Hole puncher Show Picture
    力扣算法——133.CloneGraph【M】
    力扣算法——134GasStation【M】
    力扣算法——135Candy【H】
    力扣算法——136SingleNumber【E】
    力扣算法——137SingleNumberII【M】
  • 原文地址:https://www.cnblogs.com/whx666/p/14271508.html
Copyright © 2011-2022 走看看