您的位置:首页 > 其它

【JZOJ 3823】【NOIP2014模拟9.9】遇见

2017-01-14 21:41 477 查看

Description

Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。

每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。

Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。

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都为同一个素数

Solution

这是我第一次打高斯消元,可一上来就是一道高斯消元异或方程组……

我们可以把所有约束变成一道道异或方程。

1、对于每行每列都有奇数个数被选中的约束。我们可以把第i行的每个未知数配上一个系数1。举个例子,第i行的式子为x(i−1)∗n+1^x(i−1)∗n+2^……^xi∗n==1。列的情况类似。

2、对于最终要求完全平方,我们可以拆解成n个质因数的指数为偶数。所以我们可以将n*n个数每个未知数的系数为它最多是该质因数的几次幂的倍数,例如36就是2的2次幂的倍数,同时36是3的2次幂的倍数。每个质因数也同样可以列出一个式子。

最后只要将这些高斯消元一下即可。

一些小问题

1、要注意,我们找不到当前第i位为1的式子时,我们可以将一条无意义式子(即类似0^0^0^……^0=0)移上第i位。

2、式子有可能无解。当最后你发现存在式子(类似0^0^0^……^0=1)时,则为无解。因为你不能什么都不选。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=2005,maxn1=35,mo=1e5+5,mo1=1e9+7;
int f[maxn][1000],n,i,t,j,k,l,a[maxn1][maxn1],num,h[mo],b[maxn],x,y,c[maxn],d[maxn],ans,p;
void hash(int x){
int t=x%mo;
while (h[t]!=x && h[t]) t=(t+1)%mo;
if (!h[t]) h[t]=x,b[++b[0]]=x;
}
ll mi(int x){
if (x==1) return 2;if (!x) return 1;
ll t=mi(x/2);
if (x%2) return t*t%mo1*2%mo1;return t*t%mo1;
}
int main(){
//  freopen("data.in","r",stdin);
scanf("%d",&n);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
scanf("%d",&a[i][j]);
t=a[1][1];k=0;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (a[i][j]==t) k++;
if (k==n*n && t>1 && (n%2)){
printf("0\n");
return 0;
}
for (i=1;i<=n;i++){
for (j=(i-1)*n+1;j<=i*n;j++)
f[i][j]=1;
f[i][n*n+1]=1;
}
num=n;
for (i=1;i<=n;i++){
++num;
for (j=i;j<=n*n;j+=n)
f[num][j]=1;
f[num][n*n+1]=1;
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++){
t=sqrt(a[i][j]);l=a[i][j];
for (k=2;k<=t;k++){
if (k*k>l) break;
if (l%k) continue;
hash(k);
while (!(l%k)) l/=k;
}
if (l>1) hash(l);
}
for (k=1;k<=b[0];k++){
++num;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++){
t=a[i][j];l=0;
while (!(t%b[k])) t/=b[k],l++;
f[num][(i-1)*n+j]=l%2;
}
f[num][n*n+1]=0;
}
while (num<n*n){++num;
for (j=1;j<=n*n+1;j++)
f[num][j]=f[1][j];
}
for (j=1;j<=n*n;j++){
for (i=j;i<=num;i++)
if (f[i][j]){
for (k=j;k<=n*n+1;k++)
swap(f[i][k],f[j][k]);
break;
}
for (i=j+1;i<=num;i++){
if (!f[i][j]) continue;
for (k=j;k<=n*n+1;k++)
f[i][k]=(f[i][k]^f[j][k]);
}
if (!f[j][j]){
t=1e9;
for (i=j;i<=num;i++){
k=j;
while (!f[i][k] && k<=n*n) k++;
if (k==n*n+1) k=j-1;
if (k<t) t=k,p=i;
}
for (k=j;k<=n*n+1;k++)
swap(f[p][k],f[j][k]);
}
}
for (j=num;j>=1;j--){
t=f[j][n*n+1];
if (!t) continue;
for (k=1;k<=n*n;k++)
if (f[j][k]) break;
if (k==n*n+1){
printf("0\n");return 0;
}
}
for (j=n*n;j>=1;j--){
t=f[j][n*n+1];
for (k=j+1;k<=n*n;k++)
t=(t^(f[j][k]*c[k]));
if (t) c[j]=1;
else if (!f[j][j]) ans++;
}
ans=mi(ans);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: