【888题竞赛篇】第六题,2023ICPC济南-来自知识的礼物(Gifts from Knowledge)

ICPC竞赛稀疏矩阵反转题解

更多精彩内容

这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!

256题算法特训课,帮你斩获大厂60W年薪offer

原题

2023ICPC济南真题来自知识的礼物

B站动画详解

问题分析

这道题涉及到对二进制稀疏矩阵的行进行反转,目的是让每一列最多只有一个 1。我们可以从题目描述中提炼出以下关键信息:

  1. 反转操作:可以选择任意行进行反转,也可以不反转。反转的含义是将一行从左到右的元素顺序倒置。
  2. 列中 1 的限制:我们需要找到所有使得每一列至多有一个 1 的方案。

思路分析

本题的目标是计算可以选择的行反转方案数,使得每一列至多有一个 1 1 1。由于行反转后,列中的 1 1 1 可能会改变其位置,因此需要处理不同行之间的关系,并通过图论建模找到有效的反转方案。

考虑每列的 1 1 1 位置,我们可以将其看作不同的连通块问题。具体而言,当两行之间有相同列的 1 1 1 出现时,它们需要一起被考虑,因为其中一行的反转会影响另一行。我们将问题转化为连通块的合并操作:如果两行之间有重合的 1 1 1,那么它们需要被合并为一个连通块。每个连通块可以选择反转或不反转,从而给出两种选择。

为了有效处理这些合并操作,我们使用并查集来管理这些连通块关系。最后,计算所有连通块的方案数(即 2 连通块数 2^{连通块数} 2连通块数)。需要注意的是,由于结果可能非常大,答案需要对 1 0 9 + 7 10^9 + 7 109+7 取模。

算法实现

算法的核心在于使用并查集来处理连通块的合并操作,并通过连通块的数量计算可行方案。具体步骤如下:

  1. 数据预处理与初始化: 通过读取每一行的二进制字符串,记录每列中有哪些行存在 1 1 1。这些信息可以帮助我们判断哪些行需要被合并。
  2. 连通块合并: 针对每列的 1 1 1,判断哪些行需要被合并,并使用并查集进行操作。如果存在矛盾(即同一个连通块中存在行与其反转后的自身冲突),则方案数为 0。
  3. 结果计算: 通过遍历所有连通块,计算最终方案数为 2 连通块数 / 2 2^{连通块数/2} 2连通块数/2,并对 1 0 9 + 7 10^9 + 7 109+7 取模。
  4. 特殊处理: 考虑到列数为奇数时的特殊情况,我们需要额外检查中间列是否满足条件。

代码详解

标准代码程序

C++代码

#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
vector<int> ones[N],G[N];
char s[N];
int mod = 1e9 + 7,f[N];
int find(int x)
{
   
   
	return f[x]==x?x:f[x]=find(f[x]);
}
void merge(int x,int y)
{
   
   
	f[find(x)]=find(y);
}
void addEdge(int x,int y)
{
   
   
	G[x].push_back(y);
	G[y].push_back(x);
}
void solve()
{
   
   
	int n,m,cnt=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++) ones[i].clear();
	for(int i=1;i<=n+n;i++) G[i].clear(),f[i]=i;
	for(int i=1;i<=n;i++)
	{
   
   
		cin>>s+1;
		for(int j=1;j<=m;j++) 
		{
   
   
			if(s[j]=='1') 
			{
   
   
				ones[j].push_back(i);
			}
		}
	}
	for(int i=1,j=m;i<=m/2;i++,j--)
	{
   
   
		if(ones[i].size()+</
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值