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

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

最后做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. Java入门之File类和IO流

    1.File类 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作 . 构造方法: public File(String pathname) :通过将 ...

  2. SQL SERVER数据库多having 用法

    举实例:查询大于500的数据,并按时间进行汇总排序 select  CONVERT(VARCHAR(10),DGH,23),COUNT(*) from  yxhis2017..VTBMZGHMX201 ...

  3. html隐写术,使用摩尔兹电码/莫尔兹电码存储信息 水波纹样式 Morse code

    html水波纹样式,源码直接下载,代码有注释教程,小白可以看懂. 动画啥的都做好了,效果我觉得还不错 网上文章看到xbox 工程师使用隐写术,在界面的右下角放上了含有用户激活码的水波纹样式,一般人还真 ...

  4. eclipse中的项目运行时不出现run as→java application选项

    eclipse中的运行java project时不出现run as→java application选项? 解决方案☞必须有正确的主方法,即public static void main(String ...

  5. 毕业生想学习web前端,应该怎么学才能最快找到工作?

    首先无论你要学习任何技能,必须有一个清晰的版图,什么是清晰的版图呢?首先了解你学的技术将来要从事什么工作,这个工作的条件是哪些? 然后你要有一个非常清晰的学习大纲,切记学习任何东西都要系统,不可胡乱的 ...

  6. 80%面试官不知道的dubbo → 【redis注册中心】

    dubbo的redis注册中心配置和注意事项 配置provider和consumer项目的pom.xml,增加如下2个依赖: org.apache.commons commons-pool2 2.4. ...

  7. B/S 端基于 HTML5 + WebGL 的 VR 3D 机房数据中心可视化

    前言 在 3D 机房数据中心可视化应用中,随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用. 在监控摄像机数量的不断庞大的 ...

  8. xss姿势利用

    1.定位页面可以出现xss的位置 可能会出现联合点利用 一个页面多个存储位置或者一个页面多个参数联合利用 例如输入xss 查看页面源码页面里有多个xss 或者多个参数显示 可以利用 需要注意的是有的是 ...

  9. 压敏电阻的保护作用—NDF达孚电子科技

    压敏电阻是常见的电子元器件之一,它的保护作用被大家熟知和运用.压敏电阻的主要用于在电路承受过压时进行电压钳位,吸收多余的电流以保护灵敏器件.压敏电阻的导电特性随着施加电压的变化呈非线性变化,它能保护电 ...

  10. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...