ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1242C-Sum Balance【状压dp】

2021-10-27 21:03:22  阅读:169  来源: 互联网

标签:include 数字 Sum 状压 leq sum 集合 Balance ll


正题

题目链接:https://www.luogu.com.cn/problem/CF1242C


题目大意

给出\(k\)个集合,现在从每个集合中取出一个数再把这些数放进每个集合里各一个,求能否使得所有集合的和相等,求方案。

保证所有集合中的出现过的数字都互不相同。

\(1\leq k\leq 15,1\leq n_i\leq 5000,-10^9\leq a_{i,j}\leq 10^9\)


解题思路

显然的突破口肯定是数字互不相同。

首先和不变所以每个集合的最后的和应该都是知道的记为\(sum\),记第\(i\)个集合的和为\(s_i\)。

考虑每个交换都是类似一个环形的结构,设\(b\)传给\(a\),记传出的数字为\(x_b\)和\(x_a\),那么有

\[s_a-x_a+x_b=sum\rightarrow x_b=sum-s_a+x_a \]

因为互不相同,每个数字看成一个点,那么数字\(x_a\)连接的就是\(sum-s_a+x_a\)。

然后暴力找出所有没有经过重复集合数字的环,记录\(r_S\)表示集合\(S\)的环的起点。

然后设\(f_S\)表示能否拼出集合\(S\),然后\(O(3^k)\)转移即可。

时间复杂度:\(O(k\sum n+3^k)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll K=16;
ll k,sum,s[K],f[1<<(K-1)],r[1<<(K-1)];
map<ll,ll> v;pair<ll,ll> ans[K];
void solve(ll S){
	if(!S)return;
	ll x=r[f[S]]-1e9-1;
	ll y=x,q=v[x];
	do{
		y+=sum-s[q];
		ans[v[y]]=mp(y,q);
		q=v[y];
	}while(y!=x);
	solve(S^f[S]);
	return;
}
signed main()
{
	scanf("%lld",&k);
	for(ll i=1;i<=k;i++){
		ll m;scanf("%lld",&m);
		for(ll j=1,x;j<=m;j++)
			scanf("%lld",&x),s[i]+=x,v[x]=i;
		sum+=s[i];
	}
	if(sum%k!=0)return puts("No")&0;
	sum/=k;
	map<ll,ll>::iterator it=v.begin();
	while(it!=v.end()){
		ll x=(*it).first,p=(*it).second;
		ll S=0,q=p,y=x,flag=1;
		do{
			if(!q||(S>>q-1)&1)
				{flag=0;break;}
			S|=(1<<q-1);
			y+=sum-s[q];q=v[y];
		}while(y!=x);
		if(flag)r[S]=x+1e9+1;
		++it;
	}
	ll MS=(1<<k);f[0]=-1;
	for(ll s=0;s<MS;s++){
		for(ll t=s;t;t=(t-1)&s)
			if(f[s^t]!=0&&r[t]){f[s]=t;break;}
	}
	if(!f[MS-1])return puts("No")&0;
	puts("Yes");solve(MS-1);
	for(ll i=1;i<=k;i++)
		printf("%lld %lld\n",ans[i].first,ans[i].second);
	return 0;
}

标签:include,数字,Sum,状压,leq,sum,集合,Balance,ll
来源: https://www.cnblogs.com/QuantAsk/p/15472874.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有