JZOJ 3823【NOIP2014模拟9.9】遇见

来源:互联网 发布:ubuntu root 登录 编辑:程序博客网 时间:2024/05/17 22:10

Description

Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。
每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。
Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。

Solution

取奇数个,取偶数个这种东西,是异或方程组的经典题目。
首先选不选就是是不是1的问题。
如果要求每行每列的都是奇数的话,那么给这行每个数都异或起来要等于1。
如果要完全平方数的话,那么每个质因子的出现次数要是偶数次,那么首先对每个数进行质因数分解然后 mod 2,然后对于这个质因数,每个每个数异或都异或起来之后要等于0。
然后高斯消元解异或方程组。
注意判断一下无解的情况,就是最后等式右边是1,但是前面全都是0。

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=57,mo=1000000007;int i,j,k,l,t,n,m,po,x;ll a[maxn][maxn],b[maxn],c[maxn],f[maxn*maxn][maxn*maxn],num,er[5007],da,u;bool bz[5000007],az[maxn*maxn*maxn];ll p[5000007],pp[5000007];ll o,ans;int de(int x,int y){return (x-1)*n+y;}int main(){ // freopen("fan.in","r",stdin);    scanf("%d",&n);    er[0]=1;    fo(i,1,5000)er[i]=er[i-1]*2%mo;fo(i,1,2*n)f[i][0]=1;    fo(i,1,n)fo(j,1,n){        scanf("%d",&a[i][j]),da=max(da,a[i][j]);        x=a[i][j];        for(k=2;k*k<=x;k++){            if(x%k==0){                pp[++pp[0]]=k;                while(x%k==0)x/=k;            }        }        if(x>1)pp[++pp[0]]=x;    }    sort(pp+1,pp+1+pp[0]);    fo(i,1,pp[0])if(pp[i]!=pp[i-1])p[++p[0]]=pp[i];    fo(i,1,n)fo(j,(i-1)*n+1,i*n)f[i][j]=1;    t=0;num=n;    fo(i,1,n){        t=i;++num;        fo(j,1,n)f[num][t]=1,t+=n;    }    fo(k,1,p[0]){        ++num;        fo(i,1,n){            fo(j,1,n){                x=a[i][j];t=0;                while(x%p[k]==0)t++,x/=p[k];                f[num][de(i,j)]=t%2;            }        }    }    po=1;    fo(j,1,n*n){        x=-1;        fo(i,po,num){            if(f[i][j]){                x=i;swap(f[x],f[po]);                break;            }        }             if(x==-1)u++;else po++;        az[x]=1;        fo(i,po,num){            if(f[i][j]){                fo(k,0,n*n)f[i][k]^=f[po-1][k];            }        }    }    fo(i,1,num){        x=-1;        fo(j,1,n*n){            if(f[i][j]){                x=j;break;            }        }        if(x!=-1)continue;        if(f[i][0]){            printf("0\n");            return 0;        }    }    ans=er[u];    printf("%lld\n",ans);}
1 0
原创粉丝点击