hdu 5833 Zhu and 772002 高斯消元

来源:互联网 发布:淘宝开店能够挣钱吗 编辑:程序博客网 时间:2024/06/05 21:51

Zhu and 772002

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1253    Accepted Submission(s): 444


Problem Description
Zhu and 772002 are both good at math. One day, Zhu wants to test the ability of 772002, so he asks 772002 to solve a math problem. 

But 772002 has a appointment with his girl friend. So 772002 gives this problem to you.

There are n numbers a1,a2,...,an. The value of the prime factors of each number does not exceed 2000, you can choose at least one number and multiply them, then you can get a number b.

How many different ways of choices can make b is a perfect square number. The answer maybe too large, so you should output the answer modulo by 1000000007.
 

Input
First line is a positive integer T , represents there are T test cases.

For each test case:

First line includes a number n(1n300),next line there are n numbers a1,a2,...,an,(1ai1018).
 

Output
For the i-th test case , first output Case #i: in a single line.

Then output the answer of i-th test case modulo by 1000000007.
 

Sample Input
233 3 432 2 2
 

Sample Output
Case #1:3Case #2:3

题意:给n个数字,每个数的最大素因子不超过2000。在n个数里面选取任意多个数出来(不能为0个),使得这几个数的乘积为一个完全平方数。问有多少种方案。


哎,大白书161页。

这是我高斯消元的第一道题,感觉并不是一道好的入门题,但是遇都遇到了,只有强行学强行写。

完全平方数性质:拥有的质因子都是偶数个。

利用这个性质,求出每个数质因子。

把所有数的乘积写成2^(x1+x2+x3..xn)*3^(x1+x2+x3...xn)*5^(x1+x2+x3...xn)*.......    (所有x的系数为1,因为系数变大,2个就会构成偶数,所有系数对2取个模)

使得这个乘积为一个完全平方数,就使每一个指数为偶数就行了。

列出n个方程,进行高斯消元就行了。理论上列n个,但是题目可能根本列不到n个。

有一个地方值得说得是,因为每个x只能为1或者0。高斯消元的时候只需要进行异或运算就行了(偶数为0,奇数为1)。

列出方程,高斯消元。怎么求解?

求解就是求出所有方程中自由元和1的个数。自由元的个数。自由元就是方程中非确定的数。自由元解释1,自由元解释2

求解自由元的个数可以用先求非自由元的个数,就是用高斯消元过后矩阵的秩就是非自由元的个数。矩阵的秩就是矩阵的非0行的数目。

自由元的值可以取1或者0,加上1的个数(1可取可不取)。其实1也可以叫做自由元,都是可取可不取。

所有最右答案就是2^(自由元个数)-1。-1是因为不可以一个数都不取。

第一次写,题解写得丑,还是看大白书吧。


#include <bits/stdc++.h>using namespace std;typedef long long LL;const int N = 1000+10;const LL mod = 1000000007;int n,m;int pri;       ///素数个数int prime[1000];int isprime[2000];int A[N][N];   ///构方程的矩阵void Init(){    pri = 1;    for(int i = 2;i <= 2000;i++){  ///素数打个表        if(!isprime[i])        for(int j = i*i;j <= 2000;j += i){            isprime[j] = 1;        }    }    for(int i = 2;i <= 2000;i++)        if(!isprime[i]) prime[pri++] = i;}int gauss(int n,int m) ///n个方程,m个变量{    int i = 1,j = 1;    int r;    while(i <= n && j <= m){        int r = 0;        for(int k = i;k <= n;k++){    ///找到当前列第一个不为0的行编号            if(A[k][j]){r = k;break;}        }        if(A[r][j]){            if(r != i){               ///交换两行                for(int k = 1;k <= m;k++)                    swap(A[r][k],A[i][k]);            }            for(int k = i+1;k <= n;k++){  ///消元                if(A[k][j]){                    for(int u = j;u <= m;u++)                        A[k][u] ^= A[i][u];                }            }            i++;        }        j++;    }    return i-1;}int main(void){    int T;    scanf("%d",&T);    Init();    int times = 1;    while(T--){        memset(A,0,sizeof A);        scanf("%d",&n);        for(int i = 1;i <= n;i++){            LL x;            scanf("%I64d",&x);            for(int j = 1;j < pri && x != 1;j++)            while(x%prime[j] == 0){ ///建矩阵                A[j][i] ^= 1;                x /= prime[j];                m = max(m,j);            }        }        int r = n-gauss(m,n);      ///n个变量,减去非自由元个数        LL ans = 1;        for(int i = 1;i <= r;i++)            ans = ans*2%mod;        ans--;        printf("Case #%d:\n%I64d\n",times++,ans);    }    return 0;}



0 0
原创粉丝点击