CF1242C. Sum Balance

题目描述

k组数,每组ni个,数互不相同

把每组数中的一个移到其他组(或者不移动),使得最终每组数的个数不变且总和相等

k<=15,ni<=5000

题解

最终的移动关系一定为若干个环

枚举每个环的起点,找到一个数补上去使得和等于平均值

因为互不相同,所以出边(找到的数)唯一

判断是否能成环,并且把对应的选择方案记下

预处理的时间为O(k*∑ni)

最后O(3^n)dp即可

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;

struct type{
	int s,x,y;
} a[75001];
int p[16]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
int b[16][5001];
int c[16];
int d[32768][16][2]; //d[][1][1] is special
int d2[16][2];
bool bz[16];
bool f[32768];
int g[32768];
int ans[16][2];
int D[16];
int n,I,J,i,j,k,l,len,S,s,L,tot;
long long Sum[16];
long long sum;

bool cmp(type a,type b)
{
	return a.s<b.s;
}

int get(long long t)
{
	int l=1,r=len,mid;
	
	while (l<r)
	{
		mid=(l+r)/2;
		
		if (a[mid].s<t)
		l=mid+1;
		else
		r=mid;
	}
	
	if (a[l].s==t)
	return l;
	return -1;
}

int main()
{
//	freopen("c.in","r",stdin);
	
	scanf("%d",&n);L=p[n]*2-1;
	fo(i,1,n)
	{
		scanf("%d",&c[i]);
		fo(j,1,c[i])
		scanf("%d",&b[i][j]),a[++len]={b[i][j],i,j},sum+=b[i][j],Sum[i]+=b[i][j];
	}
	
	if (sum%n)
	{
		printf("No
");
		return 0;
	}
	sum/=n;
	
	sort(a+1,a+len+1,cmp);
	
	fo(I,1,n)
	{
		fo(J,1,c[I])
		{
			memset(bz,0,sizeof(bz));
			
			S=p[I];
			
			tot=1;
			d2[1][0]=I;
			d2[1][1]=b[I][J];
			
			j=I;
			s=b[I][J];
			
			l=get(sum-(Sum[j]-s));
			
			while (!bz[j])
			{
				bz[j]=1;
				
				if (l==-1 || bz[a[l].x])
				break;
				
				j=a[l].x;
				s=a[l].s;
				S|=p[j];
				
				++tot;
				d2[tot][0]=j;
				d2[tot][1]=l;
				
				l=get(sum-(Sum[j]-s));
			}
			
			if (l!=-1 && a[l].x==I && a[l].y==J)
			{
				f[S]=1;
				fo(j,1,tot)
				{
					d[S][j][0]=d2[j][0];
					d[S][j][1]=d2[j][1];
				}
			}
		}
	}
	
	fo(i,1,L)
	{
		if (f[i])
		g[i]=i;
		else
		{
			for (j=(i-1)&i; j; j=(j-1)&i)
			if (f[j] && g[i^j])
			{
				g[i]=j;
				break;
			}
		}
	}
	
	if (g[L])
	{
		for (j=L; j; j^=g[j])
		{
			tot=0;
			fo(i,1,n)
			if (g[j]&p[i])
			++tot;
			
			ans[d[g[j]][1][0]][0]=d[g[j]][tot][0];
			ans[d[g[j]][1][0]][1]=d[g[j]][1][1];
			fo(i,2,tot)
			{
				ans[d[g[j]][i][0]][0]=d[g[j]][i-1][0];
				ans[d[g[j]][i][0]][1]=a[d[g[j]][i][1]].s;
			}
		}
		
		printf("Yes
");
		fo(i,1,n)
		printf("%d %d
",ans[i][1],ans[i][0]);
	}
	else
	printf("No
");
}
原文地址:https://www.cnblogs.com/gmh77/p/11813082.html