[hdu 5833 Zhu and 772002] Zhu and 772002 高斯消元求异或方程组
题意描述:给定N个数, N<=300, 每个数 1 <= ai <= 1e18, 求从这N 个数中选出若干个数相乘为完全平方数的组合数。
解题思路:高斯消元捣鼓了一两天。总算有丝丝收获。
完全平方数的每个质因子都是出现偶数次。我们可以很容易的列出一个模二异或方程组。变元可以分别用1,0 表示每个数选或者不选。然后系数a[i][j] 就是 第 j 个质因子在第i 个数中出现的是奇数次还是偶数次。
通过高斯消元,求出自由变元的个数 ,然后答案就是 2^(自由变元的个数) - 1,减一是减去所有数都不选的情况。
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
#define fst first
#define snd second
//typedef __int64 LL;
typedef long long LL;
typedef pair<int, int> PII;
const double eps = 1e-6;
const int MAXN = 300 + 5;
const int MAXM = 2000 + 5;
const int MOD = 1000000007;
int T, N, M;
LL temp, A[MAXN];
int prime[MAXM + 5];
LL factor[100][2];
int fatCnt;
void getPrime() {
memset (prime, 0, sizeof (prime) );
for (int i = 2; i <= MAXM; i++) {
if (!prime[i]) prime[++prime[0]] = i;
for (int j = 1; j <= prime[0] && prime[j] <= MAXM / i; j++) {
prime[prime[j]*i] = 1;
if (i % prime[j] == 0) break;
}
}
}
int getFactors (LL x) {
fatCnt = 0;
LL tmp = x;
for (int i = 1; prime[i] <= tmp / prime[i]; i++) {
factor[fatCnt][1] = 0;
if (tmp % prime[i] == 0) {
factor[fatCnt][0] = prime[i];
while (tmp % prime[i] == 0) {
factor[fatCnt][1]++;
tmp /= prime[i];
}
fatCnt++;
}
}
if (tmp != 1) {
factor[fatCnt][0] = tmp;
factor[fatCnt++][1] = 1;
}
return fatCnt;
}
struct Gauss {
// 等式的个数和变元的个数
int equ, var;
// 増广矩阵
int a[MAXN][MAXN];
void init() {
equ = prime[0], var = N;
for (int i = 0; i < equ; i++) {
for (int j = 0; j < var; j++) {
a[i][j] = (A[j] % prime[i + 1] == 0);
}
a[i][var] = 0;
}
}
void chg_row (int r1, int r2) {
for (int i = 0; i <= var; i++) {
swap (a[r1][i], a[r2][i]);
}
}
int run() {
int i, j, k;
int max_r;
int col;
col = 0;
for (k = 0; k < equ && col < var; k++, col++) {
max_r = k;
for (i = k + 1; i < equ; i++) {
if (abs (a[i][col]) > abs (a[max_r][col]) ) max_r = i;
}
chg_row (k, max_r);
if (a[k][col] == 0) {
k--;
continue;
}
for (i = k + 1; i < equ; i++) {
if (a[i][col] != 0) {
for (j = col; j < var + 1; j++) {
a[i][j] ^= a[k][j];
}
}
}
}
for (i = k; i < equ; i++) {
if (a[i][col] != 0) return -1;
}
if (k < var) {
return var - k;
}
return 0;
}
} gauss;
int main() {
#ifndef ONLINE_JUDGE
FIN;
// FOUT;
#endif // ONLINE_JUDGE
int cas = 0;
scanf ("%d", &T);
getPrime();
while (T --) {
scanf ("%d", &N);
for (int i = 0; i < N; i++) {
scanf ("%I64d", &temp);
getFactors (temp);
A[i] = 1;
for (int j = 0; j < fatCnt; j++) {
if (factor[j][1] & 1) A[i] *= factor[j][0];
}
}
LL res, ret;
gauss.init();
ret = gauss.run();
if (ret == -1) res = 0;
else {
res = 1;
for (int i = 1; i <= ret; i++) {
res = (res << 1) % MOD;
}
res = (res - 1 + MOD) % MOD;
}
printf ("Case #%d:\n", ++cas);
printf ("%I64d\n", res);
}
return 0;
}