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

    Codeforces Round #618 (Div. 1)

    旧题重补系列

    A

    ((x|y)-y) 就是二进制下 (x)(1)(y)(0) 的位的权值和

    (f(f(…f(f(a_1,a_2),a_3),…a_{n−1}),a_n)) 表示二进制下只有 (a_1)(1) 其他都为 (0) 的位的权值和

    枚举一下谁是 (a_1) 取个 (max)

    B

    奇数边形当然gg了...随便弄两个多边形画画发现符合条件的是中心对称的多边形

    证明是有的,只是我不会,嫖一下?

    C

    brute:枚举 (l)(1)(n) 搞一遍,每次找到 (r) 使平均值最小,这样应该是最优的吧

    性质:存在一种修改方案,每个数最多只被修改一次。

    proof:如果两次修改 ([l_1,r_1],[l_2,r_2])(有先后顺序),(l_1leq l_2leq r_1leq r_2),那么 ([l_2,r_2]) 相比于 ([r_1+1,r_2]) 多出来了 ([l_2,r_1]) 。目的是让字典序最小,那么可以得知经过修改,([l_2,r_1]) 这段都变小了,既然如此,不妨直接修改 ([l_1,r_2])(l_2leq l_1leq r_2leq r_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();
    }
    #define ll long long
    const int N = 1e6 + 10;
    int n, a[N], num[N], tp; ll s[N];
    signed main() {
        read (n);
        for (int i = 1; i <= n; ++i) read (a[i]);
        for (int i = 1; i <= n; ++i) {
            ll sum = a[i]; int cnt = 1;
            while (tp && s[tp] * cnt > sum * num[tp]) sum += s[tp], cnt += num[tp], --tp;
            s[++tp] = sum, num[tp] = cnt;
        }
        for (int i = 1; i <= tp; ++i) {
            double res = 1.0 * s[i] / num[i];
            for (int j = 1; j <= num[i]; ++j) printf ("%.9lf
    ", res);
        }
        return 0;
    }
    

    D

    性质:在图中随意找一棵生成树,每条非树边构成一个环,这些环的权值(边权异或)的线性基就是所有回路的线性基

    暂时先不考虑包含 (1) 的环,把所有和 (1) 相连的边断开,图分成了若干个连通块,对每个连通块算出“回路线性基”。原问题就成了每个线性基可以选或不选,有多少种选法弄不出 (0)

    本质不同的大小为 (5) 的线性基一共也没几种(374),先全部找出来,并预处理两种线性基合并的结果,然后一遍 (dp) 即可((f_{i,j}) 表示处理到第 (i) 块,当前所选线性基合并为 (j)

    对于包含 (1) 的环,在 (dp) 中按选不选这个环分类转移即可

    #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, mod = 1e9 + 7;
    struct edge { int v, w; } e[M];
    int n, m, cnt = 1, h[N], nxt[M], used[M];
    void add (int u, int v, int w) {
        e[++cnt] = {v, w}, nxt[cnt] = h[u], h[u] = cnt;
        e[++cnt] = {u, w}, nxt[cnt] = h[v], h[v] = cnt;
    }
    int tot, pw[30], id[1 << 16];
    #define up(x, y) ((x += y) >= mod && (x -= mod))
    struct base {
        int a[5];
        void clear () { memset (a, 0, sizeof (a)); }
        base (void) { memset (a, 0, sizeof (a)); }
        int ins (int x) {
            for (int i = 4; ~i; --i) if (x & pw[i]) {
                if (a[i]) x ^= a[i];
                else {
                    a[i] = x;
                    for (int j = 0; j < i; ++j) if (a[i] & pw[j]) a[i] ^= a[j];
                    for (int j = i + 1; j <= 4; ++j) if (a[j] & pw[i]) a[j] ^= a[i];
                    return 1;
                }
            }
            return 0;
        }
        int hsh () {
            return a[4] * pw[10] + a[3] * pw[6] + a[2] * pw[3] + a[1] * pw[1] + a[0];
        }
    } b[400];
    void find (base now) {
        int tmp = now.hsh ();
        if (!id[tmp]) id[tmp] = ++tot, b[tot] = now;
        else return;
        for (int i = 1; i < 32; ++i) {
            base t = now; if (t.ins (i)) find (t);
        }
    }
    int to[400][400];
    void get () {
        for (int i = 1; i <= tot; ++i) {
            base ta = b[i];
            for (int j = i; j <= tot; ++j) {
                base tb = b[j]; bool tag = 1;
                for (int k = 0; k < 5; k++)
                    if (ta.a[k]) tag &= tb.ins (ta.a[k]);
                if (tag) to[i][j] = to[j][i] = id[tb.hsh ()];
            }
        }
        for (int i = 1; i <= tot + 1; ++i)
            to[i][tot + 1] = to[tot + 1][i] = i;
    }
    void prework () {
        pw[0] = 1;
        for (int i = 1; i <= 20; ++i) pw[i] = pw[i - 1] << 1;
        find (*new (base)); get (); to[tot + 1][tot + 1] = tot + 1;
    }
    int vis[N], s[N], nn, ok, a[N], f[N][380], one[N], qwq[N], kk[N], qaq[N]; base now;
    void dfs (int u, int la) {
        vis[u] = 1;
        for (int i = h[u], v; i; i = nxt[i]) {
            if (used[i]) continue; used[i ^ 1] = 1; v = e[i].v;
            if (!vis[v]) s[v] = s[u] ^ e[i].w, dfs (v, u);
            else {
                if (v == 1) qwq[nn] = s[u] ^ e[i].w, qaq[nn] = 1;
                else ok &= now.ins (s[u] ^ s[v] ^ e[i].w), kk[nn] = 1;
            }
        }
    }
    signed main() {
        prework (); read (n), read (m);
        for (int i = 1, u, v, w; i <= m; ++i)
            read (u), read (v), read (w), add (u, v, w);
        vis[1] = 1;
        for (int i = h[1]; i; i = nxt[i]) one[e[i].v] = i;
        for (int i = 2; i <= n; ++i) if (!vis[i] && one[i]) {
            now.clear(); ok = 1, kk[++nn] = qwq[nn] = qaq[nn] = 0;
            s[i] = e[one[i]].w, used[one[i] ^ 1] = 1; dfs (i, 1);
            a[nn] = id[now.hsh ()]; if (!kk[nn]) a[nn] = tot + 1;
            if (!ok) --nn;
        }
        f[1][tot + 1] = 1;
        for (int i = 1; i <= nn; ++i) {
            for (int j = 1; j <= tot + 1; ++j) {
                up (f[i + 1][j], f[i][j]);
                up (f[i + 1][to[j][a[i]]], f[i][j]);
                if (qaq[i]) {
                    up (f[i + 1][to[j][a[i]]], f[i][j]);         // 多一种选择再加一遍
                    base t = b[a[i]];
                    if (!t.ins (qwq[i])) continue;
                    int k = id[t.hsh ()];
                    up (f[i + 1][to[j][k]], f[i][j]);
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= tot + 1; ++i) up (res, f[nn + 1][i]);
        printf ("%lld
    ", res);
    }
    

    E

    结论1:如果已经得到了 (1,2,3...p)(n-p+1,...n) 的位置,进行 (n-2k) 次询问,第 (i) 次询问不包含 (i) 和已经知道的位置,回答是 (1) 当且仅当 (a_i=p+1)(a_i=n-p)

    (1)(n) 的位置随意,如果不满足 (a_1leq frac{n}{2}) 换过来即可,然后可以用 (1) 去确定所有数的奇偶性,用以区分 (p+1)(n-p)。至此,我们得到了一个询问次数 (n^2) 的做法

    结论2:可以用中国剩余定理优化解法。只要得出每个数对 (3,5,7,8) 取模的余数就可以算出每个数((3 imes 5 imes 7 imes 8 ge 800))。

    先按照第一步的做法弄到 (p=4),得到 (1,2,3,4,n,n-1,n-2,n-3)。对于 (3,5,7),只要分别找到 (2,4,6),种不同取模结果的组合和 (x) 询问就可得到 (x) 的结果。

    但对于 (8) 朴素做法询问次数过多,考虑倍增优化:从(mod 2) 推到(mod4) 推到(mod 8),比如,从 (2) 推到 (4),对于奇数和偶数分别只需询问一组即可,通过分类去掉了不可能的无意义询问,大大减少了次数

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 810;
    int n, q[3], a[N], mod[N][9], p[N];
    void finish () {
        if (a[1] * 2 > n)
            for (int i = 1; i <= n; ++i) a[i] = n - a[i] + 1;
        printf ("! ");
        for (int i = 1; i <= n; ++i) printf ("%d ", a[i]);
        puts (""); exit (0);
    }
    void flush () { putchar ('
    '); fflush (stdout); }
    int get (int x, int mm) { return ((-x) % mm + mm) % mm; }
    signed main() {
        int test = 1;
        // ios::sync_with_stdio(false);
        cin >> n;
        for (int i = 1, x; i <= 4 && i * 2 <= n; ++i) {
            int cnt = 0;
            for (int j = 1; j <= n && cnt < 2; ++j) {
                if (a[j]) continue;
                printf ("? %d ", n - 2 * i + 1);
                for (int k = 1; k <= n; ++k)
                    if (j != k && !a[k]) printf ("%d ", k); flush ();
                cin >> x; if (x) q[++cnt] = j;
            }
            if (a[q[1]]) break;
            if (i == 1) {
                a[q[1]] = 1, a[q[2]] = n, p[1] = q[1], p[n] = q[2]; mod[q[1]][2] = 1, mod[q[2]][2] = 0;
                for (int j = 1; j <= n; ++j)
                    if (!a[j]) printf ("? 2 %d %d", q[1], j), flush (), cin >> mod[j][2];
            }
            else {
                if ((i & 1) == mod[q[1]][2]) a[q[1]] = i, a[q[2]] = n - i + 1, p[i] = q[1], p[n - i + 1] = q[2];
                else a[q[1]] = n - i + 1, a[q[2]] = i, p[i] = q[2], p[n - i + 1] = q[1];
            }
        }
        if (n <= 8) finish ();
    
        for (int i = 1, x; i <= n; ++i) {
            if (a[i]) continue;
            printf ("? 3 %d %d %d", p[1], p[2], i); flush (); cin >> x;
            if (x) continue;
            printf ("? 3 %d %d %d", p[2], p[3], i); flush (); cin >> x;
            mod[i][3] = x ? 1 : 2;
        }
        for (int i = 1, x; i <= n; ++i) {
            if (a[i]) continue;
            printf ("? 5 %d %d %d %d %d", p[1], p[2], p[3], p[n], i); flush (); cin >> x;
            if (x) { mod[i][5] = get (n + 6, 5); continue; }
            printf ("? 5 %d %d %d %d %d", p[1], p[2], p[4], p[n], i); flush (); cin >> x;
            if (x) { mod[i][5] = get (n + 7, 5); continue; }
            printf ("? 5 %d %d %d %d %d", p[1], p[3], p[4], p[n], i); flush (); cin >> x;
            if (x) { mod[i][5] = get (n + 8, 5); continue; }
            printf ("? 5 %d %d %d %d %d", p[2], p[3], p[4], p[n], i); flush (); cin >> x;
            mod[i][5] = x ? get (n + 9, 5) : get (n, 5);
        }
        for (int i = 1, x; i <= n; ++i) {
            if (a[i]) continue;
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[2], p[3], p[n - 3], p[n - 2], p[n - 1], i); flush (); cin >> x;
            if (x) { mod[i][7] = get (3 * n, 7); continue; }
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[2], p[3], p[n - 3], p[n - 2], p[n], i); flush (); cin >> x;
            if (x) { mod[i][7] = get (3 * n + 1, 7); continue; }
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[2], p[3], p[n - 3], p[n - 1], p[n], i); flush (); cin >> x;
            if (x) { mod[i][7] = get (3 * n + 2, 7); continue; }
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[2], p[3], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
            if (x) { mod[i][7] = get (3 * n + 3, 7); continue; }
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[2], p[4], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
            if (x) { mod[i][7] = get (3 * n + 4, 7); continue; }
            printf ("? 7 %d %d %d %d %d %d %d", p[1], p[3], p[4], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
            mod[i][7] = x ? get (3 * n + 5, 7) : get (3 * n + 6, 7);
        }
        for (int i = 1, x; i <= n; ++i) {
            if (a[i]) continue;
            if (mod[i][2] == 0) {
                printf ("? 4 %d %d %d %d", p[1], p[2], p[3], i); flush (); cin >> x;
                mod[i][4] = x ? 2 : 0;
            } else {
                printf ("? 4 %d %d %d %d", p[1], p[2], p[4], i); flush (); cin >> x;
                mod[i][4] = x ? 1 : 3;
            }
        }
        for (int i = 1, x; i <= n; ++i) {
            if (a[i]) continue;
            if (mod[i][4] == 0) {
                printf ("? 8 %d %d %d %d %d %d %d %d", p[1], p[2], p[3], p[n - 3], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
                mod[i][8] = x ? 0 : 4;
            }
            if (mod[i][4] == 1) {
                printf ("? 8 %d %d %d %d %d %d %d %d", p[2], p[3], p[4], p[n - 3], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
                mod[i][8] = x ? 5 : 1;
            }
            if (mod[i][4] == 2) {
                printf ("? 8 %d %d %d %d %d %d %d %d", p[1], p[3], p[4], p[n - 3], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
                mod[i][8] = x ? 6 : 2;
            }
            if (mod[i][4] == 3) {
                printf ("? 8 %d %d %d %d %d %d %d %d", p[1], p[2], p[4], p[n - 3], p[n - 2], p[n - 1], p[n], i); flush (); cin >> x;
                mod[i][8] = x ? 7 : 3;
            }
        }
        for (int i = 1; i <= n; ++i) {
            if (a[i]) continue;
            for (int j = 1; j <= n; ++j)
                if (j % 3 == mod[i][3] && j % 5 == mod[i][5] && j % 7 == mod[i][7] && j % 8 == mod[i][8])
                    { a[i] = j; break; }
        }
        finish ();
    }
    
  • 相关阅读:
    SQLLoader7(只导入数据文件的其中几行记录)
    SQLLoader6(一个或多个数据文件按条件导入不同的表)
    SQLLoader5(从多个数据文件导入到同一张表)
    SQLLoader4(数据文件中的列与表中列不一致情况-filler)
    SQLLoader3(数据文件没有分隔符时的导入)
    SQLLoader2(导入EXCEL或csv格式的文件)
    SQLLoader1(简单测试,以控制文件方式导入数据)
    可编程内存
    JSONP
    SSL协议
  • 原文地址:https://www.cnblogs.com/whx666/p/618-div1.html
Copyright © 2011-2022 走看看