uva 11542 Square 高斯消元变形+异或消元

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=505;
typedef int matrix[maxn][maxn];
int prime[101],vis[maxn];
int gen_primes(int n)//素数筛选
{
    memset(vis,0,sizeof(vis));
    int i,j,k=0,m;
    m=(int)sqrt(n+0.5);
    for(i=2;i<=m;i++)
        for(j=i*i;j<=n;j=j+i)
        vis[j]=1;
    for(i=2;i<=n;i++)
        if(!vis[i]){prime[k++]=i;}
    return k;
}
int guass_xor(matrix e,int m,int n)//m*n的矩阵,异或消元,返回自由变量数
{
    int i,j,k,r,u;
    i=j=0;
    while(i<m&&j<n)
    {
        r=i;
        for(k=i;k<m;k++)
        if(e[k][j]){r=k;break;}
        if(e[r][j])
        {
            if(r!=i)//提高数值稳定性
                for(k=0;k<=n;k++)swap(e[r][k],e[i][k]);
            for(u=i+1;u<m;u++)if(e[u][j])
                for(k=i;k<=n;k++)e[u][k]^=e[i][k];
            i++;//非全0式子数,即有界变量数
        }
        j++;
    }
    return n-i;
}
matrix e;
int main()
{
    int m,T;
    m=gen_primes(500);
    cin>>T;
    while(T--)
    {
        int n,i,j,k,maxp=0,ans;
        long long x;
        cin>>n;
        memset(e,0,sizeof(e));
        for(i=0;i<n;i++)
        {
            cin>>x;
            for(j=0;j<m;j++)
            while(x%prime[j]==0){maxp=max(maxp,j);x=x/prime[j];e[j][i]^=1;}
        }
        ans=guass_xor(e,maxp+1,n);
        cout<<(1LL<<ans)-1<<endl;
    }
    return 0;
}
/*
    xi=1表示选择第i个数,否则不选
    4,6,10,15的因子只有2,3,5;可分解为4=2^2*3^0*5^0->(2,0,0)...
    
    那么选出来的数的乘积就是2^(2*x1+x2+x3)*3^(x2+x4)*5^(x3+x4),要使其为完全平方数,则各个指数必须是2的倍数,
即各个指数中各个和数的异或值为0.由于相同数的异或值为0,所以可以将xi的系数换成0或1
    上例可得方程:
                x2^x3=0
                x2^x4=0
                x3^x4=0
    得到矩阵(横坐标为各素数因子,纵坐标为n个输入值)
            |0 1 1 0 |0|
            |0 1 0 1 |0|
            |0 0 1 1 |0|
    用高斯消元进行异或消元,最后得到自由变量个数ans,那么可能取法有2^ans种(0,1取法),还要减去全不取的情况
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值