这题写起来真的有点麻烦,按照官方题解的写法

先建图,然后求强连通分量,然后判断掉不符合条件的换

最后做dp转移即可

虽然看起来复杂度很高,但是n只有15,所以问题不大

#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <map>
#include <bitset>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <functional>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <deque>
#include <stack>
#include <complex>
#include <cassert>
#include <random>
#include <cstring>
#include <numeric>
#define ll long long
#define ld long double
#define null NULL
#define all(a) a.begin(), a.end()
#define forn(i, n) for (int i = 0; i < n; ++i)
#define sz(a) (int)a.size()
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define bitCount(a) __builtin_popcount(a)
template<class T> int gmax(T &a, T b) { if (b > a) { a = b; return 1; } return 0; }
template<class T> int gmin(T &a, T b) { if (b < a) { a = b; return 1; } return 0; }
using namespace std;
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string((string) s); }
string to_string(bool b) { return (b ? "true" : "false"); }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) { bool first = true; string res = "{"; for (const auto &x : v) { if (!first) { res += ", "; } first = false; res += to_string(x); } res += "}"; return res; }
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) { cerr << " " << to_string(H); debug_out(T...); }
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif const int MAXN = 75005;
vector<int> graph[MAXN];
vector<int> group[MAXN];
int dfn[MAXN], low[MAXN];
int dcnt;
int col[MAXN + 5], ccnt;
bool vis[MAXN + 5];
int stk[MAXN + 5], tp;
vector<pair<int, int>> dp[32768]; void Tarjan_scc(int u) {
dfn[u] = ++dcnt, low[u] = dcnt, vis[u] = true;
stk[++tp] = u;
for(int i = 0; i < (int)graph[u].size(); i++) {
int v = graph[u][i];
if(!dfn[v]) {
Tarjan_scc(v);
low[u] = min(low[u], low[v]);
} else if(vis[v]) low[u] = min(low[u], low[v]);
}
if(dfn[u] == low[u]) {
++ccnt;
while(true) {
col[stk[tp]] = ccnt;
vis[stk[tp]] = false;
if(stk[tp--] == u)
break;
}
}
} int main() {
int k;
while(~scanf("%d", &k)) {
tp = -1; ccnt = 0; dcnt = 0;
for(int i = 0; i < MAXN; ++i) {
dfn[i] = 0;
graph[i].clear();
group[i].clear();
} vector<ll> sum;
vector<pair<int, int> > vc;
map<ll, pair<int, int> > mp; int tot = 0;
ll allSum = 0;
for(int i = 0; i < k; ++i) {
int x; scanf("%d", &x);
ll tmpSum = 0;
for(int j = 0; j < x; ++j) {
int y; scanf("%d", &y);
vc.push_back(make_pair(y, i));
mp[y] = make_pair(tot, i);
tot ++;
tmpSum += y;
}
sum.push_back(tmpSum);
allSum += tmpSum;
}
// debug(allSum); if(allSum % k) {
printf("No\n");
continue;
} allSum /= k;
set<int> selfCircle;
set<pair<int, int>> hasEdge; // debug(allSum);
for(int i = 0, len = vc.size(); i < len; ++i) {
ll searchNum = allSum - sum[vc[i].second] + vc[i].first;
if(mp.find(searchNum) == mp.end()) continue;
else if( mp[searchNum].second == vc[i].second && mp[searchNum].first != i) {
// solve specfial condition
continue;
} else if(mp[searchNum].first == i) {
// debug(i);
selfCircle.insert(i);
} graph[i].push_back(mp[searchNum].first);
hasEdge.insert(make_pair(i, mp[searchNum].first)); debug(i, mp[searchNum].first);
} for(int i = 0; i < tot; ++i) {
if(!dfn[i]) Tarjan_scc(i);
} for(int i = 0; i < tot; ++i) {
// printf("%d ", col[i]);
group[col[i]].push_back(i);
}
// printf("\n"); for(int i = 1; i <= ccnt; ++i) {
// debug(i, group[i].size());
if(group[i].size() == 1 && selfCircle.count(group[i][0])) {
int id = group[i][0];
vector<pair<int, int> > tmpPair;
tmpPair.push_back(make_pair(vc[id].first, vc[id].second + 1));
dp[1<<vc[id].second] = tmpPair;
// debug(dp[1<<vc[id].second]);
}
else if(group[i].size() > 1) {
vector<pair<int, int> > tmpPair;
int tmp = 0;
int len = group[i].size();
bool suc = true;
for(int j = 0; j < len; ++j) {
int to = group[i][j];
if(tmp & (1<<vc[to].second)) { suc = false; break; }
tmp |= 1<<vc[to].second;
}
if(suc == false) {
continue;
} for(int j = 0; j < len; ++j) {
for(int k = 0; k < len; ++k) {
int fr = group[i][j]; int to = group[i][k];
if(hasEdge.count(make_pair(fr, to))) {
tmpPair.push_back(make_pair(vc[to].first, vc[fr].second + 1));
}
}
} dp[tmp] = tmpPair;
// debug(dp[tmp], tmp);
}
} for(int i = 0; i < (1<<k); ++i) {
for (int s=(i-1)&i; s; s=(s-1)&i) {
int t = i ^ s;
if(dp[s].size() > 0 && dp[t].size() > 0) {
dp[i] = dp[s];
dp[i].insert(dp[i].end(), dp[t].begin(), dp[t].end());
break;
}
}
} auto cmp = [&](pair<int, int> &A, pair<int, int> &B) {
return mp[A.first].second < mp[B.first].second;
}; int end = (1<<k) - 1;
if(dp[end].size() > 0 ) {
printf("Yes\n");
// debug(dp[end]);
sort(dp[end].begin(), dp[end].end(), cmp);
for(int i = 0; i < k; ++i) {
printf("%d %d\n", dp[end][i].first, dp[end][i].second);
}
} else printf("No\n"); }
return 0;
}

Codeforces Round #599 (Div. 2) E. Sum Balance的更多相关文章

  1. Codeforces Round #599 (Div. 1) C. Sum Balance 图论 dp

    C. Sum Balance Ujan has a lot of numbers in his boxes. He likes order and balance, so he decided to ...

  2. Codeforces Round #599 (Div. 2) D. 0-1 MST(bfs+set)

    Codeforces Round #599 (Div. 2) D. 0-1 MST Description Ujan has a lot of useless stuff in his drawers ...

  3. Codeforces Round #530 (Div. 2):D. Sum in the tree (题解)

    D. Sum in the tree 题目链接:https://codeforces.com/contest/1099/problem/D 题意: 给出一棵树,以及每个点的si,这里的si代表从i号结 ...

  4. Codeforces Round #599 (Div. 2)

    久违的写篇博客吧 A. Maximum Square 题目链接:https://codeforces.com/contest/1243/problem/A 题意: 给定n个栅栏,对这n个栅栏进行任意排 ...

  5. Codeforces Round #599 (Div. 2) A,B1,B2,C 【待补 D】

    排序+暴力 #include<bits/stdc++.h> using namespace std; #define int long long #define N 1005000 int ...

  6. Codeforces Round #530 (Div. 2) D. Sum in the tree 树上贪心

    D. Sum in the tree 题意 给出一颗树,奇数层数的点有值,值代表从1到该点的简单路的权值的和,偶数层数的点权值被擦去了 问所有节点的和的最小可能是多少 思路 对于每一个-1(也就是值未 ...

  7. Codeforces Round #599 (Div. 2) B1. Character Swap (Easy Version)

    This problem is different from the hard version. In this version Ujan makes exactly one exchange. Yo ...

  8. Codeforces Round #599 (Div. 2)D 边很多的只有0和1的MST

    题:https://codeforces.com/contest/1243/problem/D 分析:找全部可以用边权为0的点连起来的全部块 然后这些块之间相连肯定得通过边权为1的边进行连接 所以答案 ...

  9. Codeforces Round #530 (Div. 1) 1098A Sum in the tree

    A. Sum in the tree Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root ha ...

随机推荐

  1. maven突然报大量package does not exist(包不存在)问题

    遇到个问题,不知道原因,虽然已解决,但是扔不知道为什么,希望有大神帮忙解答下~~~不胜感激~~~ 国庆假期回来后,小伙伴发布测试服务器版本忽然发现报错,我咨询IT管理组近期并没有对服务器配置和权限做调 ...

  2. javascript随机点名--案例

    主要知识点涉及if选择结构判断语句.数组的定义.定时器.清除定时器.日期对象的使用. 1.HTML结构 <!DOCTYPE html> <html> <head> ...

  3. Label的作用是什么,是怎么用的?

    label标签来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到标签相关的表单控件上. 如: <form> <label for="male"&g ...

  4. Linux入门(历史与现状)

    Linux 入门之 历史与现状   Linux是一个计算机的操作系统,与windows类似,是一款系统软件.操作系统首先是一个计算机程序,使用计算机语言开发,比如C语言.VC语言.是计算机硬件和应用软 ...

  5. SQL SERVER数据库三种数据插入方式

    数据插入:INSERT INTO A(CBM,CMC) VALUES('1','测试')--单条数据插入INSERT INTO A(CBM,CMC)SELECT '1','测试'--单条数据插入INS ...

  6. Python_函数做字典的值

    当需要用到3个及以上的if...elif...else时就要考虑该方法进行简化 通过将函数名称当做字典的值,利用字典的关键字查询,可以快速定位函数,进行执行 [场景]用户查询信息,输入fn查询,执行对 ...

  7. 无 PowerShell.exe 执行 Empire 的几种姿势

    在实战中,Empire成为域渗透.后渗透阶段一大利器,而Empire是一个Powershell RAT,所以PowerShell必须要能运行Empire中几乎所有的启动方法都依赖于使用PowerShe ...

  8. 学习Spring的思考框架

    引子 很早之前听同事说:“要开会了.我都知道领导要问什么,就那几板斧.”其实领导之所以为领导,人家问的问题确实很合情合理,甚至可以说一针见血.而之所以能问出来这些合理的问题,就是因为头脑中有自己的思考 ...

  9. JavaScript如何工作:垃圾回收机制 + 常见的4种内存泄漏

    原文地址: How JavaScript works: memory management + how to handle 4 common memory leaks 本文永久链接:https://d ...

  10. Web登录中的信心安全问题

    1. 一个简单的HTML例子看看用户信息安全 标准的HTML语法中,支持在form表单中使用<input></input>标签来创建一个HTTP提交的属性,现代的WEB登录中, ...