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

来源:互联网 发布:json日期格式化输出 编辑:程序博客网 时间:2024/05/16 14:34

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(i1)n+1^x(i1)n+2^……^xin==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 longusing 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);}
1 0
原创粉丝点击