首页 > 代码库 > Light OJ 1288 Subsets Forming Perfect Squares 高斯消元求矩阵的秩

Light OJ 1288 Subsets Forming Perfect Squares 高斯消元求矩阵的秩

题目来源:Light OJ 1288 Subsets Forming Perfect Squares

题意:给你n个数 选出一些数 他们的乘积是完全平方数 求有多少种方案

思路:每个数分解因子 每隔数可以选也可以不选 0 1表示 然后设有m种素数因子 选出的数组成的各个因子的数量必须是偶数

组成一个m行和n列的矩阵 每一行代表每一种因子的系数 解出自由元的数量

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1010;
const int mod = 1000000007;
typedef int Matrix[maxn][maxn];
typedef long long LL;
int prime[maxn];
bool vis[maxn];

//返回a^p mod n 快速幂
LL pow_mod(LL a, LL p, LL n)
{
	LL ans = 1;
	while(p)
	{
		if(p&1)
		{
			ans *= a;
			ans %= n;
		}
		a *= a;
		a %= n;
		p >>= 1;
	}
	return ans;
}
void sieve(int n)
{
	int m = sqrt(n+0.5);
	memset(vis, 0, sizeof(vis));
	vis[0] = vis[1] = 1;
	for(int i = 2; i <= m; i++)
		if(!vis[i])
			for(int j = i*i; j <= n; j += i)
				vis[j] = 1;
}

int get_primes(int n)
{
	sieve(n);
	int c = 0;
	for(int i = 2; i <= n; i++)
		if(!vis[i])
			prime[c++] = i;
	return c;
}
int rank(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;
}
Matrix A;
int main()
{
	int cas = 1;
	int m = get_primes(500);
	int T;
	scanf("%d", &T);
	while(T--)
	{
		int n, maxp = 0;
		scanf("%d", &n);
		memset(A, 0, sizeof(A));
		for(int i = 0; i < n; i++)
		{
			long long x;
			scanf("%lld", &x);
			for(int j = 0; j < m; j++)
			{
				while(x % prime[j] == 0)
				{
					maxp = max(maxp, j);
					x /= prime[j];
					A[j][i] ^= 1;
				}
			}
		}
		int r = rank(A, maxp+1, n);
		printf("Case %d: %lld\n", cas++, pow_mod(2, n-r, mod)-1);
	}
	return 0;
}