Codeforces Round #599 E - Sum Balance

tarjan缩点,枚举子集。
首先avg即平均值是可以直接求出来的,我们假设第i个盒子给出去a,那么平衡需要的是,avg-sumi+a,我们把所有数字开一个map保存下来,如果有该数字,连一条有向边,从a到avg-sumi+a。
可以看到,因为题目说了unique ,所以一个点的出度是固定的,即1。现在要求所有盒子平衡,且每个盒子必须拿出来一个值。那么我们从a连出了一条有向边,如果这是一个可行解的话,那么a会处在一个环中,即a肯定也会被需要,而且还处在当前这条链中。因出度为1,环是简单环,是一条单链。
我们就能够用tarjan缩点,把这个环求出来。
一个可行解是有多个环组成的(不可能一个环,一个环的话就是x->y->z->x,那么其实可以看到x=y=z,那么数字重复了),我们通过状压和枚举子集的方式,来看最后是否能做到。
wa点:wa了很多次,没有判断这种情况,比如一个盒子中80,1,10,平均值为100,那么1会连边10,即连接自己盒子里面的数字,这里在tarjan所点的时候需要特判。同样可能会有多个可行解,对于每一个盒子来说,我们取一个就行。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5005;
ll a[20*N];
stack<int>st;
ll k,n;
int cap[20 * N], low[20 * N], dfn[20 * N];
ll sum_bx[20];
map<ll, int>mp;
struct node {
	int to, next;
}edge[40*N];
int head[40 * N];
int cnt = 0;
void addedge(int u, int v)
{
	edge[cnt].to = v;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}
vector<int> dp[(1 << 15)];
int tot, tar_tot;
int vis[20 * N];
struct scc_ {
	vector<int>vec;
	int id,sta;
}scc[20*N];
void tarjan(int u)
{
	low[u] = dfn[u] = ++tot;
	st.push(u);
	vis[u] = 1;
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(vis[v])
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (dfn[u] == low[u])
	{
		int cur = -1;
		bool flag = 0;
		do
		{
			cur = st.top(); st.pop();
			scc[tar_tot].vec.push_back(cur);
			if(scc[tar_tot].sta&(1 << (cap[cur] - 1)))flag=1;
			scc[tar_tot].sta |= (1 << (cap[cur]-1));
			vis[cur] = 0;
		} while (cur != u);
		if (flag||head[u] == -1 || scc[tar_tot].vec.size() == 1 && edge[head[u]].to != u) {
			tar_tot++;
			return;
		}
		if(dp[scc[tar_tot].sta].empty())dp[scc[tar_tot].sta].push_back(tar_tot);
		tar_tot++;
	}
}
struct ans {
	int box1;
	ll val;
	int  box2;
	ans(int b1, ll v, int b2)
	{
		box1 = b1; val = v; box2 = b2;
	}
	bool operator<(const ans &b)const {
		return box1 < b.box1;
	}
};
vector<ans>as;
int main()
{
	k = read();
	int num = 0;
	ll sum = 0;
	memset(head, -1, sizeof(head));
	upd(i, 1, k)
	{
		n = read();
		up(j, 0, n)
		{
			a[++num] = read();
			cap[num] = i;
			mp[a[num]] = num;
			sum += a[num];
			sum_bx[i] += a[num];
		}
	}
	if (sum%k) { printf("No\n"); return 0; }
	ll avg = sum / k;
	upd(i, 1, num)
	{
		ll temp = avg - sum_bx[cap[i]] + a[i];
		if (mp[temp])
		{
			addedge(i, mp[temp]);
		}
	}
	upd(i, 1, num)
	{
		if (!dfn[i])tarjan(i);
	}
	//cout << dp[8].size() << " " << dp[7].size();
	int S = (1 << k)-1;
	upd(i, 1, S)
	{
		for (int j = i&(i-1); j; j = (j-1)&i)
		{
			if (!dp[j].empty() && !dp[i^j].empty())
			{
				dp[i] = dp[i^j];
				for (auto k : dp[j])
				{
					dp[i].push_back(k);
				}
				break;
			}
		}
	}
	if (dp[S].size() == 0) {
		printf("No\n"); return 0;
	}
	else
	{
		printf("Yes\n"); 
		for (auto k : dp[S])
		{
			for (int i = 0; i < scc[k].vec.size() - 1; i++)
			{
				ans temp(cap[scc[k].vec[i]], a[scc[k].vec[i]], cap[scc[k].vec[i + 1]]);
				as.push_back(temp);
				//printf("%d\n", as.back().box2);
			}
			as.push_back(ans( cap[scc[k].vec.back()],a[scc[k].vec.back()],cap[scc[k].vec[0]]));
 
		//	printf("%d %d %d\n", as.back().box1, as.back().val, as.back().box2);
		}
		sort(as.begin(), as.end());
		for (auto k : as) {
			printf("%lld %d\n", k.val,k.box2);
		}
	}
	return 0;
}
posted @ 2019-12-22 23:43  LORDXX  阅读(193)  评论(0编辑  收藏  举报