• 2021牛客暑期多校训练营3 个人补题记录


    比赛链接:Here

    1001 - Guess and lies

    1002 - Black and white (Kruskal & 并查集)

    为了实现最少花费,需满足:在我们涂完若干个点后,其他的点对总花费不再有贡献(涂黑这些点时不花钱了)
    我们会发现 :最少,我们需要涂黑 n + m - 1 个点,且涂完这些点后 所有的行 和所有的列 会都在一个联通块里面

    举例 如下:
    不妨令 n = 2,m = 2,此时我们最少需要涂 3个点
    (g[1][1] = g[1][2] = g[2][1] = 1,g[2][2] = 3)
    为了最少花费,我们要涂的三个点显然是:(1,1),(1,2),(2,1)
    涂完(1,1)后,我们把 行1 和 列1 放到一个联通块里面
    涂完(1,2)后,我们把 行1 和 列2 放到一个联通块里面
    涂完(2,1)后,我们把 行2 和 列1 放到一个联通块里面
    到此,所有的行 和 所有的列 都在一个联通块里了,同时我们也实现了最少花费

    在这个例子中,涂黑任意三个点都可以实现 把所有的行 和 所有的列 都放在一个联通块里
    但为了 最少花费,所以我们选择的是 ((1,1),(1,2),(2,1)) 这三个点
    我们提炼出两个关键字 联通块、最小花费:连通块(并查集)+ 最小花费 = Kruskal(最小生成树)

    然后发现直接根据条件写一个并查集优化更好一点

    const int N = 1e5 + 10;
    int f[N];
    vector<pair<int, int>> v[N];
    int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        int n, m;
        ll a, b, c, d, p, ans = 0;
        cin >> n >> m >> a >> b >> c >> d >> p;
        for (int i = 1; i <= n + m; ++i) f[i] = i;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j) {
                a = (a * a * b + a * c + d) % p;
                v[a].push_back(make_pair(i, j + n));
            }
        for (int i = 0; i <= p; ++i)
            for (auto [x, y] : v[i]) {
                int xx = find(x);
                int yy = find(y);
                if (xx != yy) {
                    ans += i;
                    f[xx] = yy;
                }
            }
        cout << ans;
    }
    

    1003 - Minimum grid (二分图)

    给出 (n*n) 大小的网格,每一个最大值 (b_i) ,每一列最大值 (c_i) ,你需要对一些点赋值,使得总的赋值和最小


    将每个数值对应的行,以及每个数值对应的列分别进行存储。枚举每一个数值,范围 ([1,k])

    枚举当前数值所对应的行和列,如果当前行列可以填数,则将行和列建边,求出行和列的最大匹配数。

    当前数值的贡献为:(当前值对应的行数+当前值对应列数-最大匹配数)*当前值。
    使用 vector 进行存储,所对应的值就是:

    [[v1[now].size() + v2[now].size() - max_{pipei}] * now,(now为当前值) ]

    此处的最大匹配值可以理解为当前行和列的最大值均已经满足,可以填 0 的最大数量。

    const int N = 1e4 + 10, M = 1e6 + 10, inf = 1e8;
    int n, m, k, x;
    int mp[N][N];
    vector<int>G1[M], G2[M];
    vector<int>G[N];
    int st[N], match[N];
    
    bool dfs(int u) {
        for (auto v : G[u]) {
            if (st[v]) continue;
            st[v] = 1;
            if (match[v] == -1 || dfs(match[v])) {
                match[v] = u;
                return 1;
            }
        }
        return 0;
    }
    int cal() {
        memset(match, -1, sizeof(match));
        int res = 0;
        for (int i = 1; i <= n + n; ++i) {
            memset(st, 0, sizeof(st));
            if (dfs(i))res++;
        }
        return res;
    }
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        cin >> n >> m >> k;
        for (int i = 1; i <= n; ++i) cin >> x, G1[x].push_back(i);
        for (int i = 1; i <= n; ++i) cin >> x, G2[x].push_back(i + n);
        while (m--) {
            int x, y;
            cin >> x >> y;
            mp[x][y] = 1;
        }
        ll ans = 0 ;
        for (int now = k; now >= 1; --now) {
            if (G1[now].size() == 0 && G2[now].size() == 0) continue;
            for (int i = 1; i <= n + n; i++) G[i].clear();
            for (auto i : G1[now])
                for (auto j : G2[now])
                    if (mp[i][j - n]) G[i].push_back(j), G[j].push_back(i);
            // 建图
            ll maxpipei = cal() / 2;
            ll maxm = G1[now].size() + G2[now].size() - maxpipei;
            ans = ans + maxm * now;
        }
        cout << ans << '
    ';
    }
    

    二分图相关题:Here

    没看出这道题是二分图太丢脸了(别骂了,别骂了)

    1004 - Count

    1005 - Math (签到?)

    比赛时,我擦这公式咋推的啊,这么多人过的???

    赛后很好奇为咩能出现 IMO 的题啊!!

    https://zhuanlan.zhihu.com/p/32815892

    最后靠的打表找规律了... (打表yyds)

    [frac{x^2+y^2}{xy + 1} = k (k=1,2,...)in 1le xle yle n ]

    经过一系列的复杂计算及推演最终得出一个结论:任何x,y都会满足一个式子:

    对任意 (k>=2,a[i] = pow(k,2) * a[i-1] - a[i-2]) ,其中 (a[0]=0,a[1]=k)

    那么我们只要枚举其中较大的那个数,打表后二分即可,由于(a[2]=k^3),因此我们只需要枚举到 (1e6) ,时间复杂度 (mathcal{O}(1e6 + Tlog n))

    const int N = 1e6  + 10;
    vector<ll>a;
    ll b[N];
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        for (int k = 2; k <= 1e6; ++k) {
            b[0] = 0, b[1] = k;
            for (int i = 2; i <= 60; ++i) {
                b[i] = pow(k, 2) * b[i - 1] - b[i - 2];
                if (b[i] > 1e18 || b[i] < 0)break;
                a.push_back(b[i]);
            }
        }
        sort(a.begin(), a.end());
        a.erase(unique(a.begin(), a.end()), a.end());
        int _; for (cin >> _; _--;) {
            ll n;
            cin >> n;
            cout << upper_bound(a.begin(), a.end(), n) - a.begin() + 1 << "
    ";
        }
    }
    

    贴一下 nagisa_菜鸡桑的思路和推导过程

    这道题一拿到手应该大部分人和我一样想到打表。打出一部分表后,我们发现,任意数 ((x,x^3)) 都符合条件。

    接下来,设 (k(xy + 1) = x^2 + y ^2) ,此时固定 (x) 整理方程为 (y^2 - kxy - k + x^2 = 0)

    之所以固定 (x) 是为了接下来便于枚举 (x)

    由韦达定理(伟大定理)(y_1 + y_2 = kx)

    • 我们现在知道 ((x,y)) 符合条件,那么也就说明 ((y,x)) 也成立,那么我们可以通过 ((x,kx - y)) 找出以 (y) 作为第一个元素的数对,即 ((y,一个数))
    • 我们现在知道 ((x,y)) 符合条件,因此 一个数 = (ky - x) ,即我们得到的新的数对为 ((y,ky - x))

    此时再回头看 ((x,x^3)) 代入

    ((x,x^3)) 此时 (k=x^2)

    ((x^3,x^5-x))

    ...

    无限套娃下去。(有点类似于gcd)
    之后就是把打出来的第二元素放进数组里,排序然后二分就行了。

    1006 - 24dian

    为咩我都没看出规律

    等巨佬给我讲一下思路把

    // 待补
    

    1007 - Yu Ling(Ling YueZheng) and Colorful Tree

    1008 - Ling Qiu, Luna and Triple Backpack

    1009 - Kuriyama Mirai and Exclusive Or (树状数组维护差分)

    这里是一个调了超级久的树状数组发现错了的蒟蒻(菜鸡

    正解是用树状数组维护写一个差分数组

    const int N = 6e5 + 10;
    int n, q, a[N], aa[N];
    bool b[N][30];
    
    void update(int l, int x) {
        for (int i = 0, j = 1; i < 30; ++i, j <<= 1) {
            if (x & j and l <= n) aa[l] ^= j;
            int k = (((x >> i) + 1) << i) - x + l;
            if (k <= n) b[k][i] ^= 1;
        }
    }
    
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        cin >> n >> q;
        for (int i = 1; i <= n; ++i )cin >> a[i];
        while (q--) {
            int op, l, r, x;
            cin >> op >> l >> r >> x;
            if (op) {
                update(l, x);
                update(r + 1, x + r - l + 1);
            } else
                aa[l] ^= x, aa[r + 1] ^= x;
        }
        for (int i = 0, k = 1; i < 30; i++, k <<= 1) {
            for (int j = 1; j <= n; ++j) {
                if (j + k <= n)
                    b[j + k][i] ^= b[j][i];
                if (b[j][i])
                    aa[j] ^= k;
            }
        }
        for (int i = 1; i <= n; ++i) {
            aa[i] ^= aa[i - 1];
            cout << (a[i] ^ aa[i]) << " 
    "[i == n];
        }
    }
    

    1010 - Counting Triangles (签到?)

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    namespace GenHelper {
    unsigned z1, z2, z3, z4, b, u;
    unsigned get() {
        b = ((z1 << 6)^z1) >> 13;
        z1 = ((z1 & 4294967294U) << 18)^b;
        b = ((z2 << 2)^z2) >> 27;
        z2 = ((z2 & 4294967288U) << 2)^b;
        b = ((z3 << 13)^z3) >> 21;
        z3 = ((z3 & 4294967280U) << 7)^b;
        b = ((z4 << 3)^z4) >> 12;
        z4 = ((z4 & 4294967168U) << 13)^b;
        return (z1 ^ z2 ^ z3 ^ z4);
    }
    bool read() {
        while (!u) u = get();
        bool res = u & 1;
        u >>= 1; return res;
    }
    void srand(LL x) {
        z1 = x;
        z2 = (~x) ^ 0x233333333U;
        z3 = x ^ 0x1234598766U;
        z4 = (~x) + 51;
        u = 0;
    }
    }
    using namespace GenHelper;
    bool edge[8005][8005];
    LL a[8005];
    int main() {
        LL n, seed;
        cin >> n >> seed;
        srand(seed);
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++) {
                edge[j][i] = edge[i][j] = read();
                if (edge[i][j])  a[i]++, a[j]++;
            }
        LL ans = 0;
        for (int i = 0; i < n; i++)
            ans += a[i] * (n - a[i] - 1);
        cout << n * (n - 1) * (n - 2) / 6 - ans / 2;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    0Day – 2011.1.20[From B4A]
    0Day – 2011.1.16[From B4A]
    ubuntu 桌面下方的面板(任务栏)恢复方法
    Delphi WebBrowser用法几则浅谈
    0Day – 2011.1.3[From B4A]
    0Day – 2011.1.8[From B4A]
    0Day – 2011.1.6[From B4A]
    0Day – 2011.1.10[From B4A]
    0Day – 2011.01.21[From B4A]
    0Day – 2011.1.7[From B4A]
  • 原文地址:https://www.cnblogs.com/RioTian/p/15057877.html
Copyright © 2020-2023  润新知