jzoj3823 遇见 [高斯消元解异或方程组]

31 篇文章 0 订阅

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

分解质因数后,就是裸的高斯消元求自由元个数。
质因数个数就算最大也只有3000个左右,因为每一个最多就10个,而且往后还是会越来越少以至于每个都是1的。

注意判断无解的情况,所有系数都为0,但结果=1

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#define mo 1000000007
#define mxn 31
#define hc 10000007
#define zz(x,y) (((x)-1)*n+(y))
typedef long long ll;
using namespace std;
int ans,n,a[mxn][mxn],h[hc],bz[hc],o,loc,st[mxn],now,mxf,tot,pr[5000];
int g[5000][901],us[5000];
int hash(int x) {
    loc=x%hc;
    while (h[loc]!=0 && h[loc]!=x) {
        loc=(loc==hc-1)?1:(loc+1);
    }
    if (h[loc]==0) tot++,pr[tot]=x;
    h[loc]=x;
    return loc;
}
ll ksm(ll x,ll y) {
    if (y==0) return 1;
    if (y==1) return x;
    ll k=ksm(x,y>>1);
    return k*k%mo*ksm(x,y&1)%mo;
}
int f0,s;
void solve() {
    for (int i=1; i<=n*n; i++) {
        f0=0;
        for (int j=1; j<=tot; j++) if (us[j]==0 && g[j][i]!=0) {f0=j; break;}
        if (f0==0) {
            ans++;
            continue;
        }
        us[f0]=true;
        for (int j=1; j<=tot; j++) 
            if (us[j]==0 && g[j][i]==1) {
                for (int k=0; k<=n*n; k++) g[j][k]^=g[f0][k];
            }
        for (int j=1; j<=tot; j++) {
            s=0;
            if (us[j]==0 && g[j][0]==1) {
                for (int k=1; k<=n*n; k++) s+=g[j][k];
                if (s==0) {
                    cout<<"0"<<endl;
                    exit(0);
                }
            }
        }

    }
}
int main() {
    cin>>n; 
    int t,cnt,k;
    for (int i=1; i<=n; i++) 
        for (int j=1; j<=n; j++) {
            scanf("%d",&a[i][j]); t=a[i][j];
            for (int z=2; z*z<=a[i][j]; z++) {
                if (t==1) break;
                if (t%z==0) {
                    cnt=0;
                    while (t%z==0) t/=z,cnt++;
                    if (cnt==1) {
                        k=hash(z);
                        if (bz[k]==0) bz[k]=++tot;
                        g[bz[k]][zz(i,j)]=1;
                    }
                }
            }
            if (t!=1) {
                k=hash(t);
                if (bz[k]==0) bz[k]=++tot;
                g[bz[k]][zz(i,j)]=1;
            }
        }
    for (int i=1; i<=n; i++) {
        tot++; g[tot][0]=1;
        for (int j=1; j<=n; j++) g[tot][zz(i,j)]=1;
    }   
    for (int i=1; i<=n; i++) {
        tot++; g[tot][0]=1;
        for (int j=1; j<=n; j++) g[tot][zz(j,i)]=1;
    }
    solve();
    cout<<ksm(2,ans)<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值