[51nod1323]完美平方

探讨了在n*n矩阵中选择元素的问题,目标是找到所有可能的选择方案,使每行每列选到的元素数量为奇数个,并且所选元素的乘积为完全平方数。采用异或方程组求解自由元个数的方法,通过高斯消元实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出一个n*n的矩阵,求有多少种选择数的方案,使得每行每列均选择了奇数个数,并且选择的数的乘积为完全平方数
n<=20

Solution

完全平方数是什么,就是所有质因子的出现次数均为偶数
这样就变成了一堆奇偶的限制,异或方程组求自由元个数
高斯消元即可
感觉自己之前又打了假的高斯消元

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

#define P(x,y) ((x-1)*n+y)

const int N=905,P=9*N+2*N+5,Mo=1e9+7;

struct Prime{int p,r,bl;}pri[P];
bool cmp(Prime x,Prime y) {return x.p<y.p;}

int n,x,tot,num,ty;
bool f[P][N];

int main() {
    for(scanf("%d",&ty);ty;ty--) {
        scanf("%d",&n);tot=0;
        fo(i,1,n)
            fo(j,1,n) {
                scanf("%d",&x);
                for(int k=2;k*k<=x;k++) {
                    if (!(x%k)) pri[++tot].p=k,pri[tot].bl=P(i,j),pri[tot].r=0;
                    while (!(x%k)) x/=k,pri[tot].r++;
                }
                if (x>1) pri[++tot].p=x,pri[tot].bl=P(i,j),pri[tot].r=1;
            }
        sort(pri+1,pri+tot+1,cmp);
        memset(f,0,sizeof(f));num=0;
        fo(i,1,n) {
            num++;
            fo(j,1,n) f[num][P(i,j)]=1;
            f[num][0]=1;
        }
        fo(i,1,n) {
            num++;
            fo(j,1,n) f[num][P(j,i)]=1;
            f[num][0]=1;
        }
        fo(i,1,tot) {
            if (pri[i].p!=pri[i-1].p) {
                num++;
                fo(j,0,n*n) f[num][j]=0;
            }
            f[num][pri[i].bl]=pri[i].r%2;
        }
        int pos=1,ans=1;
        fo(i,1,n*n) {
            int now=-1;
            fo(j,pos,num) if (f[j][i]) {now=j;break;}
            if (now==-1) ans=(ans<<1)%Mo;
            else swap(f[now],f[pos]),pos++;
            fo(j,pos,num)
                if (f[j][i])
                    fo(k,0,n*n)
                        f[j][k]^=f[pos-1][k];
        }
        bool ok=1;
        fo(i,1,num) {
            bool now=0;
            fo(j,1,n*n) if (f[i][j]) {now=1;continue;}
            if (!now&&f[i][0]) {ok=0;break;}
        }
        if (!ok) {printf("0\n");continue;}
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值