CF1634E Fair Share

该篇博客探讨了一种数组划分的问题,其中要求将mmm个数组中的元素按一定规则分配到可重集LLL和RRR中,使得两者元素数量相同。通过分析,博主提出当所有数出现偶数次时问题有解,并利用图论中的二分图染色方法来判断解的存在性。在代码实现中,博主展示了如何构建图并进行黑白染色来判断解的存在,以及输出具体的划分结果。
摘要由CSDN通过智能技术生成

题意:

m m m 个数组,每个数组长度为 n i n_i ni
要在每组间恰好划分一半进可重集 L L L,剩下的进 R R R
要求判断能否找出一组划分方式,使 L L L R R R 相同。

思路:

题目要求最终的 L L L R R R 相同,考虑转化成数据中的一些互相对立的关系,从而想到建图后黑白染色。

容易发现,只有所有数都出现了偶数次才有解,于是可以先把 No 给判掉。

考虑按如下方式建图:
定义“一组”表示一个数组中相邻两元素。

  1. 在两个相邻的,值相同的数之间连边。
  2. 在每一组之间连边。

可知若两数之间有边,则它们所对应的组也一定联通。

所以在最终的图中,不会出现长度为奇数的环,即它是一个二分图。

这样再黑白染色一下就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define mk(a,b) make_pair(a,b)
const int maxn=400005;
int head[maxn],mx,tim,edgenum,m,color[maxn],n[maxn],b[maxn],d[maxn],cnt[maxn];
map<pair<int,int>,int>mat;
vector<pair<int,int> >c[maxn];
vector<int>a[maxn];
struct node{
	int to,nxt;
}edge[maxn];
void add(int u,int v){
	edgenum++;
	edge[edgenum].to=v;
	edge[edgenum].nxt=head[u];
	head[u]=edgenum;
}
void dfs(int u,int col){
	color[u]=col;
	for(int e=head[u];e;e=edge[e].nxt){
		int v=edge[e].to;
		if(color[v]) continue;
		dfs(v,(col==1?2:1));
	}
}
int main(){
	scanf("%d",&m);
	int tot=0;
	for(int i=1;i<=m;i++){
		scanf("%d",&n[i]);
		for(int j=1;j<=n[i];j++)
			scanf("%d",&b[++tot]),a[i].push_back(b[tot]);
	}
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=m;i++)
		for(int j=0;j<a[i].size();j++)
			a[i][j]=lower_bound(b+1,b+tot+1,a[i][j])-b;
	tot=0;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n[i];j++)
			mat[mk(i,j)]=++tim;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n[i];j++){
			if(j%2==0){
				add(mat[mk(i,j-1)],mat[mk(i,j)]);
				add(mat[mk(i,j)],mat[mk(i,j-1)]);
			}
			cnt[a[i][j-1]]++;
			c[a[i][j-1]].push_back(mk(i,j));
			d[++mx]=a[i][j-1];
		}
	}
	for(int i=1;i<=mx;i++) 
		if(cnt[d[i]]%2!=0){
			printf("NO");
			return 0;
		}
	for(int i=1;i<=mx;i++)
		for(int j=0;j<c[i].size();j++){
			if(j%2==1){
				add(mat[c[i][j-1]],mat[c[i][j]]);
				add(mat[c[i][j]],mat[c[i][j-1]]);
			}
		}
	for(int i=1;i<=tim;i++)
		if(!color[i]) dfs(i,1);
	printf("YES\n");
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n[i];j++){
			int id=mat[mk(i,j)];
			if(color[id]==1) printf("L");
			else printf("R");
		}
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值