QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#770588#7900. Gifts from KnowledgeShallowMapleWA 23ms67432kbC++144.1kb2024-11-21 22:31:062024-11-21 22:31:06

Judging History

你现在查看的是最新测评结果

  • [2024-11-21 22:31:06]
  • 评测
  • 测评结果:WA
  • 用时:23ms
  • 内存:67432kb
  • [2024-11-21 22:31:06]
  • 提交

answer

/*
题意:给定一个01矩阵,可以选择将每一行是否进行左右翻转,求让每一列最多有一个1的方案数
思路:首先是答案肯定是0的情况:如果对于第 i 列和第 n - i + 1 列的 1 的数量之和大于2,那么肯定是无法做到每一列至多一个 1 ,方案数就是0
然后看如何翻转:
1:如果第 i 列和第 n - i + 1 列的 1 的数量之和小于等于 1 那么这 个 1 所在的一行翻转和不翻转都可以
2:如果第 i 列和第 n - i + 1 列的 1 的数量之和为2
  (1):如果这两个 1 在同一列,那么这两行(指的是这两个1所在的行)必须翻转一个
  (2):如果这两个 1 不在同一列,那么这两行(同上)必须要不都翻转,要不都不翻转
接着如何实现:
我们使用一个互斥并查集:我们定义 i 为翻转这一行,i + n 为不翻转这一行
我们定义 i1 ,i2 分别是 2 中两个 1 所在的行
对于 2.(1):我们将 (i1, i2 + n)以及 (i1 + n, i2)这两对点合并
对于 2.(2):我们将 (i1, i2)以及 (i1 + n, i2 + n)这两对点合并
最后如果存在(i, i + n)在一个联通块,那就是互斥了,方案数是0
当所有约束条件都加进并查集后,最终的连通块数量k决定了可以选择的翻转方案数。
每个连通块可以选择翻转或不翻转),那么总的方案数就是每个连通块有 2 种选择,最终方案数为 pow(2, k)。
然而最终的答案是 pow(2, k / 2),而不是 pow(2, k),是因为每两个互斥的行(组成一个连通块)会共享一个翻转状态。
每个连通块之间有 2 种可能的选择(要么都翻转,要么都不翻转),而不仅仅是每行独立地有 2 种选择
*/

#include<bits/stdc++.h>
#define endl '\n'
#define int long long

using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;

const int N = 2e6 + 5, mod = 1e9 + 7;
int n, m, k, x, y, T;
int fa[N];
string str[N];

int getfa(int x){
	if(fa[x] != x) fa[x] = getfa(fa[x]);
	return fa[x];
}

void merg(int a, int b){
	int af = getfa(a), bf = getfa(b);
	if(af != bf) fa[af] = bf;
}


ll fastpow(ll a, ll n){
	ll base = a, res = 1;
	while(n){
		if(n & 1) res = (res * base) % mod;
		base = (base * base) % mod;
		n >>= 1;
	}
	return res;
} 

void solve()
{
	cin >> n >> m;
	for(int i = 1; i <= 2 * n; i ++){
		fa[i] = i;
	}
	
	for(int i = 1; i <= n; i ++){
		cin >> str[i];
		str[i] = " " + str[i];
	}
	
	vector<int> cnt(m + 10, 0);
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++){
			if(str[i][j] == '1') cnt[j] ++;
		}
	
	if(m % 2 == 1){
		if(cnt[(m + 1) / 2] > 2){
			cout << 0 << endl;
			return;
		}
	}
	for(int i = 1; i <= m; i ++){
		if(cnt[i] + cnt[m + 1 - i] > 2){
			cout << 0 << endl;
			return;
		}
	}
	
	for(int i = 1, j = m; i <= j; i ++, j --)
	{
		vector<int> v1, v2;
		for(int r = 1; r <= n; r ++){
			if(str[r][i] == '1') v1.push_back(r); //vector记录每对 列和其镜像列 的1的行号
			if(str[r][j] == '1') v2.push_back(r); //且保证每个vector最多只有两个1
		}
		if(v1.size() == 2) merg(v1[0], v1[1] + n), merg(v1[0] + n, v1[1]); //如果这两个 1 在同一列,那么这两行必须翻转一个
		if(v2.size() == 2) merg(v2[0], v2[1] + n), merg(v2[0] + n, v2[1]); //如果这两个 1 在同一列,那么这两行必须翻转一个
		//如果这两个 1 不在同一列,那么这两行必须要不都翻转,要不都不翻转
		for(int ii = 0; ii < v1.size(); ii ++)
			for(int jj = 0; jj < v2.size(); jj ++)
				merg(v1[ii], v2[jj]), merg(v1[ii] + n, v2[jj] + n);
	}
	
	for(int i = 1; i <= n; i ++){
		if(getfa(fa[i]) == getfa(fa[i] + n)){
			cout << 0 << endl;
			return;
		}
	}
	
	//统计连通块数量
	int cntt = 0;
	for(int i = 1; i <= 2 * n; i ++){
		if(i == getfa(i)) cntt ++;
	}
	int res = 0ll;
	res = fastpow(2, cntt / 2);
	cout << res % mod << endl;
}

signed main()
{
	ios::sync_with_stdio(false), cin.tie(0);
	
	cin >> T;
	while(T--) solve();
	
	return 0;
}


详细

Test #1:

score: 100
Accepted
time: 7ms
memory: 67432kb

input:

3
3 5
01100
10001
00010
2 1
1
1
2 3
001
001

output:

4
0
2

result:

ok 3 number(s): "4 0 2"

Test #2:

score: 0
Accepted
time: 19ms
memory: 66932kb

input:

15613
10 10
0000000000
0000000000
0000000000
0000000000
0000000000
0000000000
0000000000
0000000000
0000000000
0000000000
15 8
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
1 5
00000
5 9
000000000
000000000
0000...

output:

1024
32768
2
32
32768
128
32
16
16
2
16384
16384
128
128
32768
8192
128
64
16384
2
4
2
4096
16
4096
1024
32768
32768
16384
8
128
2
16
4096
8192
32768
8192
8192
16
16384
16384
256
128
8
256
8
4096
512
2
4
32
32
2
64
512
1024
32768
32768
2
64
16384
16
8192
16
256
16
64
8192
8192
64
1024
2
32768
2
4
51...

result:

ok 15613 numbers

Test #3:

score: -100
Wrong Answer
time: 23ms
memory: 66396kb

input:

15759
9 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
5 15
010000000000000
000000000000000
000000000000000
000100000000000
000100000000000
14 12
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000...

output:

512
16
16384
512
1024
4096
32768
4
2
512
512
512
512
8
2
256
16
4096
512
64
16
4096
512
32
32768
8192
32
2048
128
16
4096
64
32768
256
32
16384
8
512
32
2048
8
16
1024
2048
128
64
32
8
512
8
8192
256
8192
32768
2
8
512
512
256
32
2
2048
8192
8
64
8
2
16384
32768
32768
1024
4096
16384
16384
128
256
4...

result:

wrong answer 2380th numbers differ - expected: '0', found: '2'