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

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

最后做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. spring5 源码深度解析----- 事务增强器(100%理解事务)

    上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的,也讲解了Spring是如何将有配置事务的类配置上事务的,实际上也就是用了AOP那一套,也讲解了Advisor,pointcut验 ...

  2. 教你如何判断URL的好坏

    1.最核心-网站整体内容质量2.关键词整理拓展及关键词布局3.网站外部链接建设4.网站内链建设合理5.面包屑导航6.友情链接7.404页面网站的SEO站外优化+SEO外链建设 层级:三层为好,301重 ...

  3. 移动端网页常用meta

    今天在对前公司的某直播室前端进行改版时,整理了一下平时移动端页面开发时,最常用的meta.如下: <!--定义页面制作者,可以留姓名,也可以留联系方式--> <meta name=& ...

  4. 异常:微信小程序tabBar不生效

    app.json全局tabBar设置tabBar不显示 由于小程序的机制问题,首页的tabBar第一个导航必须是首页 "pages": [ "pages/index/in ...

  5. Jenkins项目构建

    一:新建项目 (1)点击新建,输入项目名称--构建一个自由风格的软件项目,点击ok (2)创建项目名称,选择节点标签 (3)构建触发器-----设置每两分钟执行一次 其中有5个参数 (*****) 第 ...

  6. Ubuntu 搜狗输入法输入异常

    电脑放置一段时间,不使用.过了一会,再使用 sogou 输入法的时候,发现,输入法不起作用了. 切花到用户目录 ~/.config 里面 rm -rf Sogou* 删除搜狗的配置文件,退出当前账户, ...

  7. 深入了解一下HTTP缓存机制

    HTTP 缓存机制作为 web 性能优化的重要手段,是Web 开发知识体系库中的一个基础环节,但是对于很多学习者来说,仅仅只是知道浏览器会对请求的静态文件进行缓存,但是为什么被缓存,缓存是怎样生效的, ...

  8. luogu P3878 [TJOI2010]分金币

    [返回模拟退火略解] 题目描述 今有 nnn 个数 {ai}\{a_i\}{ai​},把它们分成两堆{X},{Y}\{X\},\{Y\}{X},{Y},求一种分配使得∣∑i∈Xai−∑i∈Yai∣|\ ...

  9. Spring Boot入门(一):搭建Spring Boot项目

    从本篇博客开始,我们开始进入Spring Boot的世界,它的出现使Spring的开发变得更加简洁,因此一经推出受到众多程序员的喜爱. 作为Spring Boot系列的第一篇博客,我们先来讲解下如何搭 ...

  10. JS中==运行机制

    1. 判断两边是否有NaN,如果有则一律返回false 2.判断两边是否含有布尔值,如果有的话则将true转化为1,false转化为0. 3.遇到null或者undefined,则不会进行类型转换,它 ...