[Codeforces 1242C]Sum Balance
Description
给你 \(k\) 个盒子,第 \(i\) 个盒子中有 \(n_i\) 个数,第 \(j\) 个数为 \(x_{i,j}\)。现在让你进行 \(k\) 次操作,第 \(i\) 次操作要求从第 \(i\) 个盒子中取出一个元素(这个元素最开始就在该盒子中),放入任意一个你指定的盒子中,要求经过 \(k\) 次操作后
- 所有盒子元素个数和最开始相同;
- 所有盒子元素总和相等
询问是否存在一种操作方式使之满足,若存在,输出任意一种方案即可。
\(1\leq k\leq 15,1\leq n_i\leq 5000,|x_{i,j}|\leq 10^9\)
Solution
由题,容易发现,对于任意一个盒子,会从其中拿出一个数,再从别处(或自己拿出的)添加一个数进来。
我们将数的拿出放入关系抽象成边,即从第 \(i\) 个盒子中拿出的数要放入 \(j\) 中,那么建边 \(i\rightarrow j\)。
因为这张图要求每个节点入度和出度均为 \(1\),显然这张图只能是若干个无相交的环构成的。
现在,我们考虑所有的拿出放入关系:
假设我要从第 \(i\) 个盒子中拿出元素 \(x\),那么要使得这个盒子满足最终条件,应该被放入的元素为 \(S-sum_i+x\),其中 \(S\) 为最终每个盒子的元素总和,\(sum_i\) 表示第 \(i\) 个盒子最初的元素总和。
那么我们建边 \(x\rightarrow S-sum_i+x\)(注意:此时图与之前建的图不同)。我们需要在这张图中找到所有满足下列条件的环:
- 环上每个元素属于不同盒子;
- 环上每种盒子只出现一次
用 \(dfs\) 找到这些环之后我们可以将盒子状压。具体地,令 \(f_i\) 表示状态 \(i\) 中所有的盒子构成的满足条件的图是否存在。转移枚举子集 \(dp\)。
若 \(f_{2^k-1}=1\) 即有解。注意另开数据记录转移关系,方便输出方案。
Code
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N = 5000*15+5, B = (1<<15)+5;
map<ll, int> mp;
int k, n[20], id[N], kp[N], tot;
int bin[20], x[16][5005], f[B], ok[B], p[B], vis[N], s[N], top;
ll sum[20], S;
vector<int> to[N], re[B];
int l[20], r[20];
void dfs(int u, int st) {
if (vis[u]) {
int now = 0;
for (int i = top; i; i--) {
now |= bin[id[s[i]]-1];
if (u == s[i]) break;
}
if (!ok[now]) {
ok[now] = 1;
for (int i = top; i; i--) {
re[now].pb(s[i]);
if (u == s[i]) break;
}
}
return;
}
if (st&bin[id[u]-1]) return;
st |= bin[id[u]-1], vis[u] = 1, s[++top] = u;
for (auto v : to[u]) dfs(v, st);
vis[u] = 0, --top;
}
int main() {
bin[0] = 1;
for (int i = 1; i <= 15; i++) bin[i] = bin[i-1]<<1;
scanf("%d", &k);
for (int i = 1; i <= k; i++) {
scanf("%d", &n[i]);
for (int j = 1; j <= n[i]; j++)
scanf("%d", &x[i][j]), mp[x[i][j]] = ++tot,
kp[tot] = x[i][j], id[tot] = i, sum[i] += x[i][j];
S += sum[i];
}
if (S%k) {puts("No"); return 0; }
S /= k;
for (int i = 1; i <= k; i++)
for (int j = 1; j <= n[i]; j++)
if (mp.count(S-sum[i]+x[i][j])) to[mp[x[i][j]]].pb(mp[S-sum[i]+x[i][j]]);
for (int i = 1; i <= tot; i++)
dfs(i, 0);
f[0] = 1;
for (int i = 0; i < bin[k]; i++)
if (f[i]) {
int C = i^(bin[k]-1);
for (int j = C; j; j = (j-1)&C)
if (ok[j])
f[i|j] = 1, p[i|j] = i;
}
if (!f[bin[k]-1]) {puts("No"); return 0; }
int x = bin[k]-1;
while (x) {
int U = x-p[x];
for (auto i : re[U]) {
l[id[mp[S-sum[id[i]]+kp[i]]]] = S-sum[id[i]]+kp[i],
r[id[mp[S-sum[id[i]]+kp[i]]]] = id[i];
}
x = p[x];
}
puts("Yes");
for (int i = 1; i <= k; i++)
printf("%d %d\n", l[i], r[i]);
return 0;
}
[Codeforces 1242C]Sum Balance的更多相关文章
- 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 ...
- Codeforces 85D Sum of Medians(线段树)
题目链接:Codeforces 85D - Sum of Medians 题目大意:N个操作,add x:向集合中加入x:del x:删除集合中的x:sum:将集合排序后,将集合中全部下标i % 5 ...
- Codeforces Round #599 (Div. 2) E. Sum Balance
这题写起来真的有点麻烦,按照官方题解的写法 先建图,然后求强连通分量,然后判断掉不符合条件的换 最后做dp转移即可 虽然看起来复杂度很高,但是n只有15,所以问题不大 #include <ios ...
- Codeforces 1442D - Sum(找性质+分治+背包)
Codeforces 题面传送门 & 洛谷题面传送门 智商掉线/ll 本来以为是个奇怪的反悔贪心,然后便一直往反悔贪心的方向想就没想出来,看了题解才发现是个 nb 结论题. Conclusio ...
- Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)
Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...
- codeforces 616E Sum of Remainders (数论,找规律)
E. Sum of Remainders time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces 85D Sum of Medians
传送门 D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standa ...
- Codeforces 616E - Sum of Remainders
616E Sum of Remainders Calculate the value of the sum: n mod 1 + n mod 2 + n mod 3 + - + n mod m. As ...
- 数据结构(线段树):CodeForces 85D Sum of Medians
D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standard i ...
随机推荐
- Java中参数始终是按值传递
Java中参数始终是按值传递. public class Main { public static void main(String[] args) { int x = 5; change(x); S ...
- SQL Server 数据库启动过程(用户数据库加载过程的疑难杂症)
前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...
- nginx+upsync+consul 构建动态nginx配置系统
参考: http://www.php230.com/weixin1456193048.html [upsync模块说明.性能评测] https://www.jianshu.com/p/76352ef ...
- C语言学习笔记01——C语言概述
作者:Eventi 出处:http://www.cnblogs.com/Eventi 欢迎转载,也请保留这段声明.谢谢! 1 C语言的起源 1972年,贝尔实验室的丹尼斯·里奇(Dennis Ritc ...
- 玩机之HUAWEI_Nova
Nova是一款挺早的机型了.最开始使用华为就觉得这一款最好挺好用,屏幕小巧功能强大.当然也离不开手机,最早的TWRP就是在此机型上初步尝试成功,也算学习,那时候还没有玩过.这部手机算是改机最完美的一部 ...
- Python全栈开发相关课程
Python全栈开发 Python入门 Python安装 Pycharm安装.激活.使用 Python基础 Python语法 Python数据类型 Python进阶 面向对象 网络编程 并发编程 数据 ...
- 小知识:讲述Linux命令别名与资源文件的区别
别名 别名是命令的快捷方式.为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用.语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令.重要的 ...
- ps 修补工具
最近刚好遇到需要p图去除水印,这里将ps去除水印的使用记录下来已备翻阅 1.需求图片(如下),使用软件 photo shop cc 2017(以下简称ps) 2.操作 2.1方法一 使用五点修复画笔工 ...
- Docker 基础篇 入门篇
1.Docker入门 1.为什么要用docker? 相比于传统: 部署非常慢 成本非常高 资源浪费 难于迁移和扩展 可能会被限定硬件厂商 由于物理机的诸多问题,后来出现了虚拟机 一个物理机可以部署多个 ...
- Appscan漏洞 之 加密会话(SSL)Cookie 中缺少 Secure 属性
近期 Appscan扫描出漏洞 加密会话(SSL)Cookie 中缺少 Secure 属性,已做修复,现进行总结如下: 1.1.攻击原理 任何以明文形式发送到服务器的 cookie.会话令牌或用户凭证 ...