您的位置:首页 > 其它

JZOJ 3823【NOIP2014模拟9.9】遇见

2017-01-14 21:20 288 查看

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: