Description
Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。
每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。
Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。
Input
第一行是一个数正整数n。接下来是n行n列的矩阵。
Output
一个数,即方案数对于1000000007取模后的余数。
Sample Input
输入1:
2
1 1
1 2
输入2:
2
620 620
620 620
Sample Output
输出1:
1
输出2:
2
Data Constraint
第一类:对于30%的数据 n<=4 Aij<=10
第二类:对于50%的数据 n<=10 n*n个数分解质因数后的不同素数个数不超过5个
第三类:对于80%的数据 n<=15 Aij<=1000000000
第四类:对于100%的数据 n<=30 Aij<=1000000000
在第三类(不属于第二类)的数据中 有10%的数据满足Aij都为同一个素数
思路
高斯消元。
本蒟蒻第一次打高斯消元
首先,题目叫我们凑成完全平方数,所以果断分解质因数,保留指数奇偶。
然后可以列出方程组,设X[i,j]表示第i行第j列的数选或不选
那么对于每一行,每一列,显然是该行的X异或起来值为1
对于每个质数,那就是每格质数的指数*X异或起来值为0
于是可以解异或方程组 。
于是,高斯消元即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define num(i,j) (((i-1)*n)+(j))
using namespace std;
const int N=40,mo=1000000007;
int n,m,c[N][N],p[5555],pri[11111],a[5555][N][N];
int f[5555][N*N];
long long ans;
void init()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
scanf("%d",&c[i][j]);
int x=c[i][j];
for(int k=2;k*k<=x;k++)
if(x%k==0)
{
pri[++pri[0]]=k;
while(x%k==0) x/=k;
}
if(x>1) pri[++pri[0]]=x;
}
sort(pri+1,pri+pri[0]+1);
for(int i=1; i<=pri[0]; i++)
if(pri[i]!=pri[i-1]) p[++p[0]]=pri[i];
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
int x=c[i][j];
for(int k=1; k<=p[0]; k++)
while(x%p[k]==0) a[k][i][j]^=1,x/=p[k];
}
}
void make()
{
for(int i=1; i<=n; i++)
{
f[i][0]=1;
for(int j=1; j<=n; j++) f[i][num(i,j)]=1;
}
for(int i=1; i<=n; i++)
{
f[n+i][0]=1;
for(int j=1; j<=n; j++) f[n+i][num(j,i)]=1;
}
m=n+n;
for(int k=1; k<=p[0]; k++)
{
f[++m][0]=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) f[m][num(i,j)]=a[k][i][j];
}
}
void doit()
{
int num=0;
ans=1;
int pos=1;
for(int i=1; i<=n*n; i++)
{
bool q=0;
for(int j=pos; j<=m; j++)
if(f[j][i])
{
swap(f[pos],f[j]),q=1;
break;
}
if(!q) num++;
else pos++;
for(int j=pos; j<=m; j++)
if(f[j][i])
for(int k=0; k<=n*n; k++) f[j][k]^=f[pos-1][k];
}
for(int i=1; i<=m; i++)
{
bool q=0;
for(int j=1; j<=n*n; j++)
if(f[i][j]) {q=1;break;}
if(q) continue;
if(f[i][0]) ans=0;
}
for(int i=1; i<=num; i++) ans=ans*2%mo;
}
int main()
{
init();
make();
doit();
printf("%lld\n",ans);
return 0;
}