题意:
有
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 给判掉。
考虑按如下方式建图:
定义“一组”表示一个数组中相邻两元素。
- 在两个相邻的,值相同的数之间连边。
- 在每一组之间连边。
可知若两数之间有边,则它们所对应的组也一定联通。
所以在最终的图中,不会出现长度为奇数的环,即它是一个二分图。
这样再黑白染色一下就可以了。
代码:
#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;
}