首页 > 其他分享 >P9731 [CEOI2023] Balance 题解

P9731 [CEOI2023] Balance 题解

时间:2024-10-17 11:11:52浏览次数:1  
标签:head val P9731 int 题解 vis MAXN ans Balance

首先考虑 \(S=2\) 怎么做,我们把它转化为图论问题。对于每一行的两个点的颜色连一条无向边,那我们相当于要给这些边定向。最后要求 \(|in_u-out_u| \le 1\)。会发现这个要求很像欧拉回路。

但是欧拉回路是要求每个点的入度和出度相等,怎么办呢?我们再建一个超级源点,向每个奇数度数的点连边。这样跑一遍欧拉回路,最后忽略和超级源点相连的边即可。

问题变为了 \(S > 2\) 怎么做。因为题目说 \(S\) 是 \(2\) 的次幂,这让我们想到分治。每一次只需要要求每种颜色在左一半的出现次数和在右一半的出现次数差不超过 \(1\)。但是题目要求我们只能在行内交换,所以假设我们现在分治到 \([l,r]\),我们就连边 \((a_{i,j},a_{i,mid+1+j-l})\)。会发现这样一定有解。

时间复杂度 \(O(nS \log S)\)。

//dzzfjldyqqwsxdhrdhcyxll
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4e6 + 10;
int n,s,t,head[MAXN],cnt,vis[MAXN << 1],ans[MAXN << 1],tot,d[MAXN << 1];
struct Node {int u,v,nxt;}e[MAXN << 1];
inline void Add(int u,int v) {
//	cout << "u = " << u << " v = " << v << endl; 
	e[cnt] = {u,v,head[u]};
	head[u] = cnt++;
}
vector <int> a[MAXN];
inline int Get(int i,int j) {
	return max(t,n * s) + (i - 1) * s + j; 
}
inline void dfs(int u) {
	for(int &i = head[u]; ~ i;i = e[i].nxt) {
		if(vis[i]) continue;
		int now = e[i].v;
		vis[i] = vis[i ^ 1] = 1;
		dfs(now);
		if(i==-1){
			break;
		}
	}
	ans[++tot] = u;
//	cout << u << " ";
}
inline void solve(int l,int r) {
	int mid = (l + r) >> 1;
	for(int i = 1;i <= n;i++) {
		for(int j = l;j <= mid;j++) {
			if(a[i][j] == a[i][mid + 1 + j - l]) continue;
			Add(a[i][j],Get(i,j));
			Add(Get(i,j),a[i][j]);
			Add(Get(i,j),a[i][mid + 1 + j - l]);
			Add(a[i][mid + 1 + j - l],Get(i,j));
			d[a[i][j]]++;
			d[a[i][mid + 1 + j - l]]++;
		}
	}
	if(l == 3 && r == 4) {
//		cout << "dddd = " << d[3] << endl;
	}
	for(int i = 1;i <= n;i++) {
		for(int j = l;j <= r;j++) {
			if(d[a[i][j]] % 2 == 1) {
				d[a[i][j]]++;
				Add(0,a[i][j]);
				Add(a[i][j],0);
			}
		}
	}
	tot = 0;
//	dfs(0);
	for(int i = 1;i <= n;i++) {
		for(int j = l;j <= r;j++) {
//			cout << endl << endl << endl;
			dfs(a[i][j]);
		}
	}
	for(int i = 1;i <= tot;i++) {
		if(l == 3 && r == 4) {
//			cout << "ans = " << ans[i] << endl;
		}
		if(ans[i] > max(t,n * s)) {
			int val = ans[i] - max(t,n * s);
			int x = (val - 1) / s + 1;
			int y = (val % s == 0 ? s : val % s);
			if(ans[i - 1] == a[x][y]);
			else swap(a[x][y],a[x][mid + 1 + y - l]);
		}
	}
	d[0] = 0;
	head[0] = -1;
	for(int i = 1;i <= n;i++) {
		for(int j = l;j <= r;j++) {
			d[a[i][j]] = 0;
			head[a[i][j]] = -1;
			d[Get(i,j)] = 0;
			head[Get(i,j)] = -1;
		}
	}
	for(int i = 0;i < cnt;i++) {
		vis[i] = 0;
		d[e[i].u] = 0;
		d[e[i].v] = 0;
		head[e[i].u] = -1;
		head[e[i].v] = -1;
	}
//	memset(d,0,sizeof d);
//	memset(vis,0,sizeof vis);
//	memset(head,-1,sizeof head);
	cnt = 0;
//	cout << "l = " << l << " r = " << r << endl;
//	for(int i = 1;i <= n;i++,puts(""))
//		for(int j = 1;j <= s;j++) cout << a[i][j] << " ";
	if(r - l == 1) return; 
	solve(l,mid),solve(mid + 1,r);
	return; 
} 
signed main() { 
//	freopen("P9731_23.in","r",stdin);
	memset(head,-1,sizeof head);
	cin >> n >> s >> t;
	for(int i = 1;i <= n;i++) {
		a[i].resize(s + 5); 
	}
	for(int i = 1;i <= n;i++) {
		for(int j = 1;j <= s;j++) {
			cin >> a[i][j];
		}
	}
	solve(1,s);
	for(int i = 1;i <= n;i++,puts("")) {
		for(int j = 1;j <= s;j++) {
			cout << a[i][j] << " ";
		}
	}	
	return 0;
}
/*
3 8 5
2 3 5 1 5 5 4 4
3 5 1 1 2 3 2 2
1 3 3 2 2 5 3 4
3 2 5
4 1 
3 5
2 3
*/

标签:head,val,P9731,int,题解,vis,MAXN,ans,Balance
From: https://www.cnblogs.com/Creeperl/p/18471627

相关文章

  • 常见ElasticSearch 面试题解析(上)
    前言ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTfulweb接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,......
  • 2024-10-17每日一题题解
    最大子段和题目描述给出一个长度为\(n\)的序列\(a\),选出其中连续且非空的一段使得这段和最大。样例输入72-43-12-43样例输出4题解tips:无脑暴力法:枚举每一段区间,再对每一段区间求和,时间复杂度为\(O(n^3)\),会超时(n为1e5,则应该在\(O(nlogn)\)的时间范围内)......
  • 【题解】【记忆化递归】——Function
    【题解】【记忆化递归】——FunctionFunction题目描述输入格式输出格式输入输出样例输入#1输出#1提示数据规模与约定1.思路解析2.AC代码Function通往洛谷的传送门题目描述对于一个递归函数w......
  • PTA L1系列题解(C语言)(L1_073 -- L1_080)
    L1-073人与神题目内容:L1-073人与神-团体程序设计天梯赛-练习集(pintia.cn)跨界大神L.PeterDeutsch有一句名言:“Toiterateishuman,torecursedivine.”(迭代的是人,递归的是神)。本题就请你直接在屏幕上输出这句话。输入格式:本题没有输入。输出格式:在一行中输......
  • HIAST Collegiate Programming Contest 2024(非完全题解)
    C题HZY做的,等他补题解//#pragmaGCCoptimize("O3,unroll-loops")//#pragmaGCCtarget("avx2,bmi,bmi2,lzcnt,popcnt")////如果在不支持avx2的平台上将avx2换成avx或SSE之一#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecon......
  • 「CEOI2023」Balance
    感觉这种题天克我啊。。题目给出了\(S=2^k\)的限制,让我们有一些奇怪的思考,再加上有\(S=2\)的部分分,我们可以考虑从\(S=2\)拓展到任意情况。故我们先研究\(S=2\)的情况。我们对颜色建点,对于每一行的两种颜色之间连一条边。然后我们考虑钦定每一条边的方向以表示这一行的......
  • HNCPC2024 2024湖南省赛 题解
    目录写在前面I签到C签到E二进制,枚举,子集DPK转化,分层图最短路A枚举,DP,简单计算几何J单调性,枚举,数据结构HDP,字符串,KMPD莫比乌斯反演,枚举写在最后写在前面比赛地址:https://codeforces.com/gym/105423。以下按个人难度向排序。利益相关:现场赛Au。没有和去年一样整场犯唐......
  • [题解]NOIP2018模拟赛 plutotree
    题目描述给定一棵有\(n\)个节点的树,根节点为\(1\),节点\(i\)有权值\(w[i]\)。这棵树非常奇怪,它的每个叶子结点都有一条连向根节点的权值为\(0\)的边。给定\(q\)次询问,每次给定\(u,v\),请计算出一条\(u\)到\(v\)的路径(每条边最多经过\(1\)次),最小化该路径上的点权之和,并在其基础上最......
  • P10353 [PA2024] Grupa permutacji 题解
    神秘!在这些排列生成的置换群\(G\)里,若\(\exists\pi\inG\)使得\(\pi_i=k,\pi_j=l\),则所有这些\((k,l)\)被同样数量的\(\pi\inG\)通过前述方法得出。证明:设\(\pi(i,j)=(k,l),\pi'(i,j)=(k',l')\)(意义前述),则\(\pi^{-1}\circ\pi'(k,l)=(k',l')......
  • [题解]P3952 [NOIP2017 提高组] 时间复杂度
    P3952[NOIP2017提高组]时间复杂度我们把循环的嵌套关系看做树形结构,梳理一下\(3\)种情况:直接跳过当前子树:\(x,y\in\mathbb{N}\),且\(x>y\)。\(x=\tt{"n"},y\in\mathbb{N}\)。不跳过,并在处理完所有子节点后追加\(n\)的时间复杂度:\(x\in\mathbb{N},y=\tt{"n"}\)。......