Codeforces40E[Number Table]
Codeforces40E[Number Table]
解法一,如果有一维很小,可以考虑状压dp之类的,显然非常不优秀。
解法二,如果n*m较小,可以考虑,设出每个位置是否为-1,解xor线性方程组。再bitset优化一下之类的。然而,还是没有充分利用到题目给的特殊信息。
解法三,根据 (0 ≤ k < max(n, m)),我们可以直到必然存在一空行或列,而通过改变这一行的值,可以控制,每一列都为奇数个-1,所以问题就转化为每行有奇数个-1的方法数,这个很容易计算,现在要考虑我们填充的那个空行的合法性,即他是否有奇数个-1。可以列出等式:
(-1的总数) = (m列-1数目的和)=(n行-1数目的和) = (m个奇数和) = ((n-1)个奇数和+空行里填的-1的数目)
移项可得: 空行里填的-1的数目 = (m个奇数和) - (n-1)个奇数和
显然只有当m和n奇偶性一致时,符合条件。其他情况无解。
#include <bits/stdc++.h> typedef long long ll; using namespace std; int a[1111][1111], n, m, k, b[1111][1111]; ll P, fc[1111]; inline void chg() { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)b[j][i]=a[i][j]; swap(n,m); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)a[i][j]=b[i][j]; } inline int ck(int x){ for(int i=1;i<=m;++i)if(a[x][i]!=0)return 0; return 1; } inline ll cal(int x) { ll num0=0,num1=0; for(int i=1;i<=m;++i) { if(!a[x][i])++num0; else if(a[x][i]==-1)++num1; } if(num0==0&&(num1&1)==1) return 1; if(num0==0&&(num1&1)==0) return 0; return fc[num0-1]; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;++i){int x,y,z; scanf("%d%d%d",&x,&y,&z); a[x][y]=z; } scanf("%I64d",&P); if((n&1)!=(m&1)){ puts("0");return 0; } if(n<m)chg(); fc[0]=1%P; for(int i=1;i<=n;++i)fc[i]=(fc[i-1]*2LL)%P; int f=0; ll ans=1LL; for(int i=1;i<=n;++i) { if(!f&&ck(i)){ //first kong hang f=1; continue; } ans=(ans*cal(i))%P; } printf("%I64d\n",ans); return 0; }