HDU 5833 Zhu and 772002(高斯消元)

题意:给n个数,从n个数中抽取x(x>=1)个数,这x个数相乘为完全平方数,求一共有多少种取法,结果模1000000007。

思路:每个数可以拆成素数相乘的形式,例如:

 x1   2=2^1 * 3^0 * 5^0;

 x2   3=2^0 * 3^1 * 5^0;

 x3   4=2^2 * 3^0 * 5^0;

 x4   5=2^0 * 3^0 * 5^1;

 x5   6=2^1 * 3^1 * 5^0;

 x6   15=2^0 * 3^1 * 5^1;

用xi表示第i个数选或不选,xi的取值为0或1;因为相乘结果为完全平方数,所以最后的完全平方数表示成素数相乘的形式后,每个素数的幂一定是偶数,即模2等于0:

 2   (x1+2*x3+x5)%2=0

 3   (x2+x5+x6)%2=0

 5   (x4+x6)%2=0

将上面的式子转化为异或方程组,求解有m个自由变量,每个自由变量都可以取0或1,最终答案为2^m-1(去掉全0的情况);

#include <bits/stdc++.h>
using namespace std;
#define MAXN 2000
int prime[MAXN+5];
int a[MAXN+5][305];
int free_num;
int free_x[MAXN];
int x[310];
int equ,var;
const int mod=1000000007;
void getprime()
{
    int i,j;
    memset(prime,1,sizeof(prime));
    prime[0]=prime[1]=0;
    for(i=2;i<=MAXN;i++)
    {
        if(prime[i])
            prime[++prime[0]]=i;
        for(j=1;j<=prime[0]&&i*prime[j]<=MAXN;j++)
        {
            prime[i*prime[j]]=0;
            if(i%prime[j]==0)
                break;
        }
    }
}
void geta(int id,long long num)
{
    int i;
    i=1;
    while(num!=1)
    {
        while(num%prime[i]==0)
        {
            num/=prime[i];
            a[i-1][id]^=1;
        }
        i++;
    }
}
//返回值为-1表示无解,为0是唯一解,否则返回自由变元个数
int Gauss()
{
    int max_r, col, k;
    free_num = 0;
    for(k = 0, col = 0; k < equ && col < var; k++, col++)
    {
        max_r = k;
        for(int i = k ; i < equ; i++)
            if(abs(a[i][col]==1)
            {
                max_r = i;
                break;
            }
        if(a[max_r][col] == 0)
        {
            k--;
            free_x[free_num++] = col; //自由变元
            continue;
        }
        if(max_r != k)
        {
            for(int j = col; j < var+1; j++)
                swap(a[k][j],a[max_r][j]);
        }
        for(int i = k+1; i < equ;i++)
            if(a[i][col] != 0)
                for(int j = col; j < var+1;j++)
                    a[i][j] ^= a[k][j];
    }
    for(int i = k;i < equ;i++)
        if(a[i][col] != 0)
            return -1;
    if(k < var)return var-k;
    return 0;
}
int main()
{
    int ans;
    int t;
    int n;
    int i;
    int cas;
    int freex;
    long long num;
    scanf("%d",&t);
    getprime();
    //printf("%d\n",prime[0]);
    for(cas=1;cas<=t;cas++)
    {
        memset(a,0,sizeof(a));
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%I64d",&num);
            geta(i,num);
        }
        equ=prime[0];
        var=n;
        freex=Gauss();
        //printf("::%d\n",freex);
        if(freex==-1)
            ans=0;
        else if(freex==0)
            ans=0;
        else
        {
            ans=1;
            for(i=0;i<freex;i++)
            {
                ans=(2*ans)%mod;
            }
            ans--;
        }
        printf("Case #%d:\n%d\n",cas,ans);
    }
    return 0;
}
View Code

 

posted @ 2016-08-15 18:49  vwqv  阅读(266)  评论(0编辑  收藏  举报