Description
Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。
每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。
Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。
分解质因数后,就是裸的高斯消元求自由元个数。
质因数个数就算最大也只有3000个左右,因为每一个最多就10个,而且往后还是会越来越少以至于每个都是1的。
注意判断无解的情况,所有系数都为0,但结果=1
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#define mo 1000000007
#define mxn 31
#define hc 10000007
#define zz(x,y) (((x)-1)*n+(y))
typedef long long ll;
using namespace std;
int ans,n,a[mxn][mxn],h[hc],bz[hc],o,loc,st[mxn],now,mxf,tot,pr[5000];
int g[5000][901],us[5000];
int hash(int x) {
loc=x%hc;
while (h[loc]!=0 && h[loc]!=x) {
loc=(loc==hc-1)?1:(loc+1);
}
if (h[loc]==0) tot++,pr[tot]=x;
h[loc]=x;
return loc;
}
ll ksm(ll x,ll y) {
if (y==0) return 1;
if (y==1) return x;
ll k=ksm(x,y>>1);
return k*k%mo*ksm(x,y&1)%mo;
}
int f0,s;
void solve() {
for (int i=1; i<=n*n; i++) {
f0=0;
for (int j=1; j<=tot; j++) if (us[j]==0 && g[j][i]!=0) {f0=j; break;}
if (f0==0) {
ans++;
continue;
}
us[f0]=true;
for (int j=1; j<=tot; j++)
if (us[j]==0 && g[j][i]==1) {
for (int k=0; k<=n*n; k++) g[j][k]^=g[f0][k];
}
for (int j=1; j<=tot; j++) {
s=0;
if (us[j]==0 && g[j][0]==1) {
for (int k=1; k<=n*n; k++) s+=g[j][k];
if (s==0) {
cout<<"0"<<endl;
exit(0);
}
}
}
}
}
int main() {
cin>>n;
int t,cnt,k;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) {
scanf("%d",&a[i][j]); t=a[i][j];
for (int z=2; z*z<=a[i][j]; z++) {
if (t==1) break;
if (t%z==0) {
cnt=0;
while (t%z==0) t/=z,cnt++;
if (cnt==1) {
k=hash(z);
if (bz[k]==0) bz[k]=++tot;
g[bz[k]][zz(i,j)]=1;
}
}
}
if (t!=1) {
k=hash(t);
if (bz[k]==0) bz[k]=++tot;
g[bz[k]][zz(i,j)]=1;
}
}
for (int i=1; i<=n; i++) {
tot++; g[tot][0]=1;
for (int j=1; j<=n; j++) g[tot][zz(i,j)]=1;
}
for (int i=1; i<=n; i++) {
tot++; g[tot][0]=1;
for (int j=1; j<=n; j++) g[tot][zz(j,i)]=1;
}
solve();
cout<<ksm(2,ans)<<endl;
}