Description
Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。
每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。
Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。
Solution
我们设 Pi,j 表示 (i,j) 这个格子选不选。
现在有两个条件:
1. 使得每行每列都有奇数个数被选中
2. 选中的数字的乘积是完全平方数
我们先看条件1,那么要满足:
Pi,1⊕Pi,2⊕⋯⊕Pi,n=1(1≤i≤n)
P1,j⊕P2,j⊕⋯⊕Pn,j=1(1≤j≤n)
(这里的⊕是异或的意思)
再看条件2:
我们把所有数分解质因数,记出现的质数为
p1,p2,⋯,pm
。
定义
f(k,x)
表示
x
这个数是包含了奇数还是偶数个第
举个例子:
72=23⋅32
那么
f(2,72)=1,f(3,72)=0
然后对于第
k
个质数,我们可以得出式子:
然后我们得出了一些式子,这就是很经典的异或方程组模型,用高斯消元求自由元个数
t
,答案就是
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 31
#define M 3001
#define ll long long
#define mo 1000000007
#define mod 300007
using namespace std;
int a[M][N*N];
int n;
int bh[M][N*N];
int pr[M];
int h[mod],wz[mod];
int w;
bool hash(int x)
{
int p=x%mod;
while(h[p] && h[p]!=x) p=(p+1)%mod;
w=p;
if(h[p]==x) return true;
return false;
}
int g(int x,int y){
return (x-1)*n+y;
}
int gauss(int tot,int m)
{
int i=0,j=0;
while(i<m && j<tot)
{
int r=i;
fo(k,i,m) if(a[k][j]) {r=k;break;}
if(a[r][j])
{
if(r!=i)
fo(k,0,tot) swap(a[i][k],a[r][k]);
fo(l,i+1,m-1) if(a[l][j])
fo(k,i,tot) a[l][k]^=a[i][k];
int t=0;
i++;
}
j++;
}
fo(i,0,m-1)
{
int t=0;
fo(j,0,tot-1) t+=a[i][j];
if(!t && a[i][tot]==1) return -1;
}
return i;
}
int main()
{
scanf("%d",&n);
fo(i,1,n)
fo(j,1,n)
{
ll x;
scanf("%lld",&x);
int p=2;
while(p*p<=x)
{
int t=0;
bool tf=hash(p);
if(x%p==0 && !tf)
{
pr[++pr[0]]=p;
wz[w]=pr[0];
h[w]=p;
}
while(x%p==0) x/=p,t^=1;
bh[wz[w]][g(i,j)]=t;
p++;
}
if(x>1)
{
bool tf=hash(x);
if(!tf)
{
pr[++pr[0]]=x;
wz[w]=pr[0];
h[w]=x;
}
bh[wz[w]][g(i,j)]=1;
}
}
int m=0;
fo(i,1,n)
{
fo(j,1,n) a[m][g(i,j)-1]=1;
a[m][n*n]=1;
m++;
}
fo(j,1,n)
{
fo(i,1,n) a[m][g(i,j)-1]=1;
a[m][n*n]=1;
m++;
}
fo(p,1,pr[0])
{
fo(i,1,n)
fo(j,1,n)
a[m][g(i,j)-1]=bh[p][g(i,j)];
a[m][n*n]=0;
m++;
}
int t=n*n-gauss(n*n,m);
if(t==n*n+1)
{
printf("0");
return 0;
}
ll ans=1;
fo(i,1,t) ans=ans*2%mo;
printf("%lld",ans);
}