首页 > 其他分享 >CF1634E Fair Share 题解

CF1634E Fair Share 题解

时间:2024-03-09 19:33:22浏览次数:17  
标签:CF1634E idx int 题解 Share ++ vector include size

题意:

给定 \(m\) 个长度为偶数的数组,\(L, R\) 是初始为空的两个多重集。将每个数组恰好一半的数放入 \(L\),另一半放入 \(R\),要求最后 \(L=R\),要求构造方案或判断无解。

\(m \le 10^5, \sum n \le 10^5\)。

思路:

首先我们不难想到,对于同一个数组内相同的值,可以成双除去,所以我们可以简化为每个数组一个值最多有一个的情况。

然后思考这些限制,由于一个值有两个关键的信息:他的值和所属数组。这两个都要满足恰好一半。这让我们联想到建图。

构造二分图,一边是数组,一边是值,然后连边。我们现在要求一个选取边的方案,使得每个点刚好有一半的出边被选取。

这个形式等价于该图存在欧拉回路,所以我们只用找到欧拉回路,然后轮换染色即可。

很有意思的欧拉回路题。

点击查看代码
#include <iostream>
#include <cstdio>
#include <map> 
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;

int m;
vector<vector<int> > a;//原数组 
map<int, int> mp; 

int tot = 0;

struct Edge {
	int to, idx;
	Edge (int _to = 0, int _idx = 0) :
		to(_to), idx(_idx) {}
}; 

vector<Edge> e[N * 2];//二分图 
int ed = 0, dg[N * 2] = {0}; //点的度数 
void add(int u, int v) {
	dg[u]++, dg[v]++, ed++;
//	cout << u << " " <<v <<" "<<ed<<endl;
	e[u].push_back(Edge(v, ed));
	e[v].push_back(Edge(u, ed));
}

void build() {
	for (auto &i: mp)
		i.second = ++tot;
	for (int T = 0; T < m; T++) {
		vector<int> t = a[T];
		sort(t.begin(), t.end());
		for (int i = 0, j = 0; i < (int)t.size(); i++)
			if (i == (int)t.size() - 1 || t[i] != t[i + 1]) {
				if ((i - j + 1) % 2 == 1)
					add(T + 1, m + mp[t[i]]);
				j = i + 1;
			}
	}
}

int cur[N * 2] = {0};
bool vis[N * 2] = {false};
int stk[N * 2] = {0}, tp = 0;
void srh(int x) {
	for (int i = cur[x]; i < (int)e[x].size(); i = cur[x]) {
		++cur[x];
		if (!vis[e[x][i].idx]) {
			vis[e[x][i].idx] = true;
			srh(e[x][i].to);
			stk[++tp] = e[x][i].idx;
		}
	}
}
bool ans[N * 2] = {false};

bool LR[N] = {false};

void fnd_sol(int T) {
	vector<pair<int, int> > t;
	for (int i = 0; i < a[T].size(); i++)
		t.push_back(make_pair(a[T][i], i)), LR[i] = false;
	sort(t.begin(), t.end());
	for (int i = 0, j = 0, k = 0; i < (int)t.size(); i++)
		if (i == (int)t.size() - 1 || t[i].first != t[i + 1].first) {
			int len = i - j + 1;
			if (len % 2 == 1) {
			//	cout << T << " " << t[i].first << " " << ans[e[i][k].idx] << endl;
				LR[t[j].second] = ans[e[T + 1][k].idx]; 
				k++, j++, len--;
			}
			for (int x = j; x <= j + len / 2 - 1; x++)
				LR[t[x].second] = false;
			for (int x = j + len / 2; x <= i; x++)
				LR[t[x].second] = true;
			j = i + 1;
		}
	for (int i = 0; i < (int)a[T].size(); i++)
		if (LR[i])
			printf("L");
		else
			printf("R");
	printf("\n");
}

int main() {
	cin >> m;
	for (int i = 1, n; i <= m; i++) {
		cin >> n;
		vector<int> t = vector<int>(n, 0);
		for (int j = 0; j < n; j++)
			cin >> t[j], mp[t[j]] = 1;
		a.push_back(t);
	}
	//首先,离散化建图去重
	build(); 
	for (int i = 1; i <= m + tot; i++)
		if (dg[i] % 2 == 1) {
			printf("NO\n");
			return 0;
		}
	//找欧拉回路
	for (int i = 1; i <= m + tot; i++)
		if (cur[i] < (int)e[i].size()) {
			srh(i);
			bool rev = (i <= m);
			//如果是 <= m -> >m 的就是 true
			//否则是 false 
			while (tp > 0) {
				ans[stk[tp]] = rev;
		//		cout << stk[tp] <<" "<<rev<<endl;
				rev = !rev, tp--;
			}
		}
	//找完了,还原方案
	printf("YES\n");
	for (int T = 0; T < m; T++) 
		fnd_sol(T);
	return 0; 
}

标签:CF1634E,idx,int,题解,Share,++,vector,include,size
From: https://www.cnblogs.com/rlc202204/p/18063189

相关文章

  • Interval GCD 题解
    题目描述给定一个长度为\(\largen\)的数组\(\largea\),以及\(\largem\)条指令(\(n\leq5\times10^5,m\leq10^5\)),每条指令可能是以下两种之一:“\(\large\operatorname{C\l\r\d}\)”,表示把\(\largea[l],a[l+1],…,a[r]\)都加上\(\larged\)。“\(\large\operatorn......
  • CF1264D2 Beautiful Bracket Sequence (hard version) 题解
    括号深度的本质,其实就是删除若干个字符以后使得左边一半全是(,右边一半全是),最终(的个数的最大值。那么就一定存在一个位置使得在这个位置以及之前的字符中(的个数等于这个字符后)的个数。考虑枚举这个位置,记它左边的(的个数为\(a\)、?的个数为\(x\),右边的)的个数......
  • [CF696B] Puzzles 题解
    首先很好想到要用树形\(dp\)。然后设\(dp_i\)为遍历到第\(i\)个点的期望时间,\(sz_i\)代表\(i\)的子树大小。发现有转移方程:\[dp_i=dp_{fa_i}+1+\sum\limits_{j\infa_i且j\nei}sz_j\timesq\]其中\(q\)为一个常数,代表在排列中\(j\)在\(i\)前的概率。很容易发......
  • 无聊的数列[题解]
    无聊的数列[link1][link2]题目大意给定一个数列\(A\)有两种操作:将数列中\(A_i\)(\(L\leqi\leqR\))加上一个等差数列(首项D公差K)查询数列中第P位数区间加上一个等差数列可以用差分来解决例原序列:000000差分序列:000000等差序列:13579(首项1......
  • 课堂练习 最大值 原题链接+题解
    题目可以去我的洛谷题库看:https://www.luogu.com.cn/problem/U412348(带数据,真难出)题解考虑两种解题方式。由于题目范围较小,可以check+暴力,如果范围大一点,可以check+二分答案。先讲check函数,小学四年级数学书说了,这种问题也被它叫做“铺地砖”问题,计算剪出的正方形数量的方......
  • 一本通 1270 混合背包 题解
    是在hydro上做的,墙裂推荐hydro的一本通题库!链接是:https://hydro.ac/d/ybttk/p/T1270。分析一下,可以分类讨论,处理的时候,零一背包(\(p_i=1\))一个,完全背包(\(p_i=0\))一个,多重背包(\(p_i>1\))一个,状态转移方程不用列的,直接去抄模板就可以啦~代码是这样的捏:#include<bits/st......
  • P6583 回首过去 题解
    P6583回首过去题解题目传送门好题。更新(2023-12-05):把代码和$\LaTeX$改得更好看了。题意简述给定正整数$n$,求出有序整数对$(x,y)$的个数,满足$1\lex,y\len$且$\dfracxy$可以表示为十进制有限小数。$1\len\le10^{12}$。前置知识数论分块解法Subtas......
  • CF1846D Rudolph and Christmas Tree 题解
    因为\(n\)个三角形有重叠部分,所以我们可以倒序处理每个三角形,并对其进行分类讨论:若当前三角形编号为\(n\),则直接将总面积加上\(\dfrac{d\timesh}{2}\)。否则,再次分出两种情况:若当前三角形的\(y_i+h>y_{i+1}\)(即编号为\(i,i+1\)的三角形有重叠),则如下图所示:......
  • CF387B George and Round 题解
    考虑采用双指针法解决此题。首先需要对\(a,b\)数组排序,并且维护两个指针\(l,r\),分别指向\(a,b\)两个数组中的元素。接着循环移动\(r\)指针,每次都尝试匹配\(a_l\)和\(b_r\):若\(a_l\leb_r\),则说明\(a_l=b_r\)或可以采用减少\(b_r\)的方式使\(a_l=b_r\),这......
  • P3670 [USACO17OPEN] Bovine Genomics S 题解
    题意给定\(2\)组字符串,每组\(n\)个,每个字符串包含\(m\)个字符。我们称一个三元组\((i,j,k)\)是合法的,当且仅当第二组的每个字符串中下标为\((i,j,k)\)的字符拼成的字符串与第一组的每个字符串中下标为\((i,j,k)\)的字符拼成的字符串均不相等。现在需要你对于给定的......