cf1242C Sum Balance 【图 + 状压】

题目链接

cf1242C

题解

题意:有K个组,每组有若干个数【所有数互异】,现在从每个组取出一个数,然后再将这些数分别放入一个组中,是否存在方案使得操作结束后每个组数字的和相等

最后相等的和是固定的,我们可以求出每个组距离结果的差值,对于这个组每个数,如果要将其取出,那么放入的一定就是这个数再减去这个差值的数值,而所有数互异,这样的值最多一个。这样每个数都可以找到一个这样匹配的数,向其连边,这样这张图中一个环就代表了一个轮换。如果我们能找到一组环,使得每个组都被包含一次,那么就是答案。
由于每个点只连出一条边,只可能形成简单环,dfs就能将其找出
最后每个环用二进制表示状态进行状压dp,即可得到结果。

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 100005,maxm = (1 << 15),INF = 0x3f3f3f3f;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
    return flag ? out : -out;
}
struct node{
    LL v,id;
}A[maxn];
inline bool operator < (const node& a,const node& b){
    return a.v < b.v;
}
LL K,n,nxt[maxn];
LL sum,av,S[20],Lack[20];
LL vis[maxn],cnt;
LL s[maxn],ent[maxn],si;
int vv[20];
void dfs(int u){
    vis[u] = cnt;
    if (!nxt[u]) return;
    if (!vis[nxt[u]]) dfs(nxt[u]);
    else if (vis[nxt[u]] == cnt){
        for (int i = 1; i <= K; i++) vv[i] = 0;
        vv[A[u].id] = true;
        for (int t = nxt[u]; t != u; t = nxt[t]){
            if (vv[A[t].id]) return;
            vv[A[t].id] = true;
        }
        s[++si] = (1 << (A[u].id - 1));
        ent[si] = u;
        for (int t = nxt[u]; t != u; t = nxt[t]){
            s[si] |= (1 << (A[t].id - 1));
        }
    }
}
void getc(){
    sort(A + 1,A + 1 + n);
    for (int i = 1; i <= n; i++){
        if (!Lack[A[i].id]) continue;
        LL x = A[i].v - Lack[A[i].id],pos = lower_bound(A + 1,A + 1 + n,(node){x,0}) - A;
        if (pos >= 1 && pos <= n && A[pos].v == x && A[pos].id != A[i].id && Lack[A[pos].id])
            nxt[i] = pos;
    }
    for (int i = 1; i <= n; i++) if (!vis[i]) ++cnt,dfs(i);
}
LL f[maxm],pre[maxm],used[maxm];
LL bi;
struct Node{
    LL id,v,to;
}B[100];
inline bool operator < (const Node& a,const Node& b){
    return a.id < b.id;
}
void dp(){
    int ini = 0;
    for (int i = 1; i <= K; i++) if (!Lack[i]) ini |= (1 << (i - 1));
    f[ini] = 1;
    for (int i = 0; i <= (1 << K) - 1; i++){
        if (!f[i]) continue;
        for (int j = 1; j <= si; j++) if (!(i & s[j])){
            int to = (i | s[j]);
            f[to] = 1;
            pre[to] = i;
            used[to] = j;
        }
    }
    int maxv = (1 << K) - 1;
    if (!f[maxv]) puts("No");
    else {
        puts("Yes");
        for (int i = maxv; i != ini; i = pre[i]){
            int j = used[i],u = ent[j];
            B[++bi] = (Node){A[nxt[u]].id,A[nxt[u]].v,A[u].id};
            for (int v = nxt[u]; v != u; v = nxt[v]){
                B[++bi] = (Node){A[nxt[v]].id,A[nxt[v]].v,A[v].id};
            }
        }
        for (int i = 1; i <= K; i++) if (!Lack[i]){
            for (int j = 1; j <= n; j++) if (A[j].id == i){
                B[++bi] = (Node){i,A[j].v,i};
                break;
            }
        }
        sort(B + 1,B + 1 + bi);
        for (int i = 1; i <= bi; i++) printf("%I64d %I64d\n",B[i].v,B[i].to);
    }
}
void work(){
    getc();
    dp();
}
int main(){
    K = read();
    for (int i = 1; i <= K; i++){
        int m = read();
        while (m--) A[++n].v = read(),A[n].id = i,sum += A[n].v,S[i] += A[n].v;
    }
    if (sum % K){puts("No"); return 0;}
    av = sum / K;
    REP(i,K) Lack[i] = S[i] - av;
    work();
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/12268902.html

时间: 2024-07-31 05:35:21

cf1242C Sum Balance 【图 + 状压】的相关文章

HDU 4845 拯救大兵瑞恩(分层图状压BFS)

拯救大兵瑞恩 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 264    Accepted Submission(s): 106 Problem Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但是幸好麦克得到了迷宫的地形图

【dp】luoguP4796 关于图 想不到是状压dp (┬_┬)

luoguP4796 题意:给定一张N个点M条边的无向图,每个点有一个颜色,所有点的颜色共有 K 种,编号为 1…K.求图上有多少条长度至少为 2 的简单路径,满足路径上的每一个点的颜色互不相同.路径上的点的连接顺序不同看作不同的两条路径. 数据范围:1?N,M?100000,1?K?5 一直朝着搜索的角度去思考,找不到什么明确的方法. 看了题解..知道需要状压,但是想不到是状压dp.............我dp果然太弱了(:′⌒`) 做法是: 设每个点的颜色是c[i],则对i这个点有一个起始

cf285 D. Permutation Sum 状压 dfs打表

题意: 如果有2个排列a,b,定义序列c为: c[i] = (a[i] + b[i] - 2) % n + 1 但是,明显c不一定是一个排列 现在,给出排列的长度n (1 <= n <= 16) 问有多少种a,b的排列的组合的方案,使得得到的c也是一个排列 排列的组合a = x,b = y 与 排列的组合a = y,b = x算是2种方案 思路: 有3个排列,不妨假设排列a 为1,2,3,...,n 这样结果再 * n! 就是答案 考虑状压dp j是一个16位的数,记录b的n个数被用了哪些数

poj1185 状压dp

poj1185   状压dp 炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20940   Accepted: 8104 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队

poj185--炮兵阵地(状压dp)

炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20169   Accepted: 7805 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击

状压DP NOI2001 炮兵阵地

司令部的将军们打算在N × M的网格地图上部署他们的炮兵部队.一个N × M的地图由N行M列组成,地图的每一格可能是山地(用"H"表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击不到.从图上可见炮兵

HDU 1565&amp;1569 方格取数系列(状压DP或者最大流)

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6206    Accepted Submission(s): 1975 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

[AC自动机+状压dp] hdu 4534 郑厂长系列故事——新闻净化

题意:中文的题目,意思就是说有很多串,每个串都有权值,权值为999的串必须出现,-999的串必须不出现.权值在-999~999之间. 然后必须出现的串不超过8个.然后给一个全为小写目标串,问最少需要删除多少个字母才能够保证必须出现的串都出现,次数一样保证权值最大.输出次数和权值. 然后根据样例,那些必须出现的串,其实权值是0. 思路: 很明显一开始建自动机构成trie图,但是需要注意的就是mark和sum的更新.个人是把所有中间的节点的sum全部赋值成了-inf. 接着只有8个必须出现的串,所以

[POJ 1185][codevs 1647][NOI 2001]炮兵阵地 状压DP

炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 23655 Accepted: 9148 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图