Uva 11542 乘积是平方数

题目链接:http://vjudge.net/contest/142484#problem/A

这个题目也是2016年CCPC网赛上面的题目,当时我是不会做的,但是大牛们都知道这是一个原题,最后给一队过了,还是大牛们厉害,其实也不是很难。

题意:

给出n个正整数,从中选出1个或者多个,使得选出来的整数乘积是完全平方数,一共有多少种选法。

分析:

"不含大于500的素数因子"——每一个数的唯一分解式。

例如: {4,6,10,15} 

4x1 = 22 * 3* 50;

6x2 = 21 * 31 * 50;

10x3= 21 * 30 * 51;

15x4 = 20* 31 * 51;

要使得乘积为平方数,那么每个分向量的指数为偶数。

就得到了方程组:

x2 + x3 = 0(mod2);

x2 + x4 = 0(mod2);

x3 + x4 = 0(mod2);

解方程:

发现有x个自由变量答案就是 2x - 1个解(全部不要题意删除);

#include <bits/stdc++.h>
using namespace std;

const int maxn = 500 + 10;
const int maxp = 100;

int vis[maxn];
int prime[maxp];


int gen_primes(int n)
{
    int m = (int)sqrt(n+0.5);
    memset(vis,0,sizeof(vis));  //是素数为 0
    for(int i=2; i<=m; i++)
    {
        if(!vis[i])
        {
            for(int j=i*i; j<=n; j+=i)
                vis[j] = 1;
        }
    }

    int c = 0;
    for(int i=2; i<=n; i++)
    {
        if(!vis[i])
            prime[c++] = i;
    }
    return c;
}

typedef int Matrix[maxn][maxn];

Matrix A;

//m 个 方程组,n 个变元
int ranks(Matrix A,int m,int n)
{
    int i=0,j=0,k,r,u;
    while(i<m&&j<n)
    {
        r = i;
        for(k=i; k<m; k++)
            if(A[k][j])     
            {
                r = k;
                break;
            }

        if(A[r][j])
        {
            if(r!=i)
                for(k=0; k<=n; k++)
                {
                    swap(A[r][k],A[i][k]);
                }

            //消元
            for(u=i+1; u<m; u++)
            {
                if(A[u][j])
                    for(k=i; k<=n; k++)
                        A[u][k] ^=A[i][k];
            }
            i++;
        }
        j++;
    }
    return i;
}

int main()
{
    int m = gen_primes(500);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,maxp = 0;
        long long x;
        scanf("%d",&n);
        memset(A,0,sizeof(A));

        for(int i=0; i<n; i++)
        {
            scanf("%lld",&x);
            for(int j=0; j<m; j++)  //对于某一个素数因子
            {
                while(x%prime[j]==0)
                {
                    maxp = max(maxp,j);     //方程组
                    x = x/prime[j];
                    A[j][i]^=1;
                }
            }
        }
        int r = ranks(A,maxp+1,n);
        printf("%lld
",(1LL<<(n-r))-1);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/TreeDream/p/6086933.html