• CodeForces 1242C Sum Balance


    CodeForces 1242C Sum Balance

    https://codeforces.com/contest/1242/problem/C

    (k) 个箱子, 第 (i) 个箱子中有 (n_i) 个数 (a_{i,1},a_{i,2},cdots,a_{i,n_i}) ,现在要从每个箱子中取出一个数, 然后再把这些数分配个每个箱子.问是否存在一种方案使得每个箱子中的数的和相等.若存在,输出方案.

    (1 le k le 15, 1 le n_i le 5000, |a_{i,j}| le 10^9)

    所有 (a_{i,j}) 两两不同

    Tutorial

    (s =dfrac 1k sum a_{i,j}) ,若 (s) 不是整数则无解.

    考虑对于 (a_{i,j}) ,假如把它取走,那么放进来的一定是 (x=s - (sum_{k = 1}^{n_i} a_{i,k}) + a_{i,j}) .建立一张图,每个节点对应一个 (a_{i,j}) ,连一条 (a_{i,j})(x) 的有向边.

    这是一张基环图,考虑对于图中的每一个环,可以在答案中出现作为排列中的环.所以用DFS找出所有的环.然后用子集和DP即可求解.

    判环部分 (O(nk)) ,DP部分 (O(3^k))

    Code

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <vector>
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    using namespace std;
    typedef long long ll;
    const int maxk = 15 + 5;
    const int maxn = 5000 + 5;
    const int maxN = maxn * maxk;
    const int maxs = 1 << 15;
    int k;
    int N;
    int c[maxk], p[maxk];
    int f[maxs], g[maxs];
    int bit[maxk];
    int bel[maxN];
    int pre[maxN];
    int rnk[maxN];
    int head[maxN];
    int tim, vis[maxN];
    ll s;
    ll sum[maxk];
    map<int, int> mp;
    vector<int> C[maxs];
    struct edge
    {
        int to, nex;
        edge(int to = 0, int nex = 0) : to(to), nex(nex) {}
    };
    vector<edge> G;
    inline void addedge(int u, int v)
    {
        G.push_back(edge(v, head[u])), head[u] = G.size() - 1;
    }
    void dfs(int u)
    {
        vis[u] = tim;
        for (int i = head[u]; ~i; i = G[i].nex)
        {
            int v = G[i].to;
            if (vis[v])
            {
                if (vis[v] != tim)
                    continue;
                vector<int> temp;
                int s = 0, ok = 1;
                for (int x = u; ; x = pre[x])
                {
                    if (s & bit[bel[x]])
                    {
                        ok = 0;
                        break;
                    }
                    s ^= bit[bel[x]];
                    temp.push_back(x);
                    if (x == v) 
                        break;
                }
                // debug("%d
    ", s);
                if (ok)
                {
                    f[s] = 1;
                    C[s] = temp;
                }
            }
            else
            {
                pre[v] = u;
                dfs(v);
            }   
        }
    }
    void travel(int s)
    {
        if (g[s] == s)
        {
            for (int i = 0; i < C[s].size(); ++i)
            {
                int u = C[s][i];
                c[bel[u]] = rnk[u];
                p[bel[u]] = bel[C[s][(i + 1) % C[s].size()]];
            }
            return;
        }
        travel(g[s]);
        travel(s ^ g[s]);
    }
    bool sol()
    {
        if (s % k)
            return 0;
        s /= k;
        memset(head, -1, sizeof(head));
        for (int i = 1; i <= N; ++i)
        {
            ll d = s - sum[bel[i]] + rnk[i];
            if (abs(d) > 1e9)
                continue;
            if (mp.count(d))
                addedge(i, mp[d]);
        }
        for (int i = 1; i <= N; ++i) if (!vis[i])
        {
            ++tim;
            dfs(i);
        }
        f[0] = 1; 
        for (int s = 1; s < bit[k]; ++s)
        {
            for (int t = s; ; t = (t - 1) & s)
            {
                if (f[t] & f[s ^ t])
                {
                    f[s] = 1;
                    g[s] = t;
                    break;
                }
                if (t == 0)
                    break;
            }
        }
        if (!f[bit[k] - 1])
            return 0;
        travel(bit[k] - 1);
        puts("Yes");
        for (int i = 0; i < k; ++i)
            printf("%d %d
    ", c[i], p[i] + 1);
        return 1;
    }
    void init()
    {
        bit[0] = 1;
        for (int i = 1; i <= k; ++i)
            bit[i] = bit[i - 1] << 1;
    }
    int main()
    {
        scanf("%d", &k);
        init();
        for (int i = 0; i < k; ++i)
        {
            int n;
            scanf("%d", &n);
            for (int j = 1; j <= n; ++j)
            {
                int x;
                scanf("%d", &x);
                int u = ++N;
                mp[x] = u;
                rnk[u] = x;
                bel[u] = i;
                sum[i] += x;
            }
            s += sum[i];
        }
        if (!sol())
            puts("No");
        return 0;
    }
    
  • 相关阅读:
    【福利】JetBrains 全家桶永久免费使用
    openlayers操作分享:如何从容的在vue中食用openlayers6
    Axios的正确食用方法
    uniapp 地图全解析+事件监听
    JS数据扁平化
    Codeforces 记录
    WP开发加载图片及文字Resource/Content说明
    根据属性获取属性名
    string和byte 数组转换的快速方法(采用unsafe)
    Code First Migrations更新数据库结构(数据迁移)
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/12878461.html
Copyright © 2020-2023  润新知