[Codeforces Beta Round #39] E. Number Table

洛谷传送门
Codeforces传送门

题意翻译

有一个 n n n m m m 列的棋盘,现在棋盘上的每个位置需要填上 1 1 1 − 1 -1 1 。 其中有 k k k 个位置已经填上了数,而其它的位置则是空的。 定义一个棋盘是好的当且仅当其每一行、每一列都满足所有数的乘积是 − 1 −1 1 。 你需要计算有多少种填数的方案是好的,答案对 p p p 取模。 0   ≤   k   &lt;   max ⁡ { n , m } 0~\leq~k~&lt;~\max\{n,m\} 0  k < max{n,m}

输入输出格式

输入格式

第一行两个正整数 n , m n, m n,m

第二行一个非负整数 k k k

以下 k k k行, 每行三个整数 x , y , v a l x,y,val x,y,val, 表示第 x x x行第 y y y列的格子已经填上了 v a l val val

最后一行一个正整数 p p p

输出格式

一行一个正整数, 表示填数的方案数对 p p p的结果。

输入输出样例

输入样例#1:
2 2
0
100
输出样例#1:
2
输入样例#2:
2 2
1
1 1 -1
100
输出样例#2:
1

解题分析

首先, 因为每个格子填成 − 1 -1 1会对一行一列造成影响, 那么显然如果 n + m n+m n+m为奇数是无解的。

注意到 k &lt; m a x ( n , m ) k&lt;max(n,m) k<max(n,m) , 那么肯定有一行或一列是空的, 我们只要保证其他行或列满足乘积为 − 1 -1 1, 这一行自然也就有唯一分配方式。所以我们直接考虑每一行的合法分配方式, 实际上就等于 2 t o t − 1 2^{tot-1} 2tot1 t o t tot tot为该行空位数)。

注意如果某一行/列已经全部填上了 1 1 1,显然就没有解了。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 1005
#define ll long long 
template <class T>
IN void in(T &x)
{
	static char c; static bool neg;
	x = 0; c = gc;
	for (; !isdigit(c); c = gc)
	if (c == '-') neg = true;
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
	if (neg) neg = false, x = -x;
}
int n, m, k, MOD;
bool vcrs[MX], vcol[MX];
int crs[MX], col[MX], tcrs[MX], tcol[MX];
ll ans = 1;
IN ll fpow(ll base, R int tim)
{
	ll ret = 1;
	W (tim)
	{
		if (tim & 1) ret = ret * base % MOD;
		base = base * base % MOD, tim >>= 1;
	}
	return ret;
}
int main(void)
{
	int x, y, foo, bar;
	in(n), in(m), in(k);
	if ((n + m) & 1) return puts("0"), 0;
	for (R int i = 1; i <= n; ++i) crs[i] = 1;
	for (R int i = 1; i <= m; ++i) col[i] = 1;
	for (R int i = 1; i <= k; ++i)
	{
		in(x), in(y), in(foo);
		vcrs[x] |= 1, vcol[y] |= 1;
		crs[x] *= foo, col[y] *= foo;
		tcrs[x]++, tcol[y]++;
	}
	in(MOD);
	for (R int i = 1; i <= n; ++i) if (tcrs[i] == m && crs[i] == 1) {return puts("0"), 0;}
	for (R int i = 1; i <= m; ++i) if (tcol[i] == n && col[i] == 1) {return puts("0"), 0;}
	for (R int i = 1; i <= n; ++i) if (!vcrs[i])
	{
		for (R int j = 1; j <= n; ++j)
		{
			if (i == j) continue;
			if (tcrs[j] >= m - 1) continue;
			ans = 1ll * ans * fpow(2, m - tcrs[j] - 1) % MOD;
		}
		return printf("%lld", ans), 0;
	}
	for (R int i = 1; i <= m; ++i) if (!vcol[i])
	{
		for (R int j = 1; j <= m; ++j)
		{
			if (i == j) continue;
			if (tcol[j] >= n - 1) continue;
			ans = 1ll * ans * fpow(2, n - tcol[j] - 1) % MOD;
		}
		return printf("%lld", ans), 0;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值