Description
一个
n×m
的棋盘,每个格子里会填
1
或
Input
第一行三个整数
n,m,k
分别表示棋盘行列数和已经填好的格子数,之后
k
行每行输入三个整数
Output
输出满足条件的方案数,将结果模 109+7 后输出
Sample Input
2 2
0
100
Sample Output
2
Solution
若 n,m 奇偶性不同显然无解(从行看整个棋盘数字乘积为 (−1)n ,从列看整个棋盘数字乘积为 (−1)m )
若 n,m 奇偶性相同,不妨设 n≥m (如果 n<m 则将棋盘转过来),由于 k<n ,故必有一行没有数字初始被填上了,那么其他行只要保证行乘积是 −1 即可,不需要考虑列乘积,因为这一行可以保证所有列乘积是 −1 ,且如果除该行外所有行乘积均为 −1 ,那么由于所有列乘积是 −1 ,进而得到该行乘积也是 −1
故只需看是否存在某行所有数字都被填上且乘积是
1
,出现则无解,如果不出现,则对于每一行(已经填满数字的不考虑),必然存在一个没填数字的位置,其他位置
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=1005;
int mod_pow(int a,int b,int c)
{
int ans=1;
while(b)
{
if(b&1)ans=(ll)ans*a%c;
a=(ll)a*a%c;
b>>=1;
}
return ans;
}
int n,m,k,p,f[maxn][maxn];
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(f,0,sizeof(f));
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(n<m)swap(a,b);
f[a][b]=c;
}
if(n<m)swap(n,m);
scanf("%d",&p);
if((n-m)&1)
{
printf("0\n");
continue;
}
int cnt=(n-1)*(m-1)-k,flag=0;
for(int i=1;i<=n;i++)
{
int num=0,temp=1;
for(int j=1;j<=m;j++)
if(f[i][j]!=0)num++,temp*=f[i][j];
if(num==m)
{
if(temp!=-1)
{
flag=1;
break;
}
cnt++;
}
}
if(flag)printf("0\n");
else printf("%d\n",mod_pow(2,cnt,p));
}
return 0;
}