Hdu-5833 Zhu and 772002(高斯消元)

43 篇文章 0 订阅
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
  
  
2 3 3 3 4 3 2 2 2
 

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


题意:给你n个数字,让你从中选出一些数字出来乘到一起,问能的到完全平方数的方案数。


分析:注意到最大的素因子最多为1997(303个),完全平方数中的所有素因子个数为偶数个,我们可以以此建立一个异或方程组,每个质因子对应一个方程,求出自由元个数的二次幂减一就是答案。


#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
using namespace std;
int T,n,tot,f[2005],F[310][310];
bool prime[2005];
void Swap(int a[310],int b[310])                         //交换 
{
	for(int i = 1;i <= n;i++) a[i] = a[i] + b[i];
	for(int i = 1;i <= n;i++) b[i] = a[i] - b[i];
	for(int i = 1;i <= n;i++) a[i] = a[i] - b[i];
}
long long ksm(long long a,long long b)
{
	long long ans = 1ll;
	while(b)
	{
		if(b & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		b >>= 1; 
	}
	return ans;
}
int main()
{
	memset(prime,1,sizeof(prime));
	prime[2] = true;
	for(int i = 2;i <= 2000;i++)
	 if(prime[i])
	  for(int j = 2*i;j <= 2000;j += i)
	   prime[j] = false;
	for(int i = 2;i <= 2000;i++)
	 if(prime[i]) f[i] = ++tot; 
	scanf("%d",&T);
	for(int t = 1;t <= T;t++)
	{
		int zy = 0;
		memset(F,0,sizeof(F));
		scanf("%d",&n);
		for(int i = 1;i <= n;i++)
		{
			long long x;
			scanf("%I64d",&x);
			for(int k = 2;k <= sqrt(x);k++)
			 while(x % k == 0)
			 {
			 	F[f[k]][i] = (F[f[k]][i] + 1) % 2; 
			 	x /= k;
			 }
			if(x != 1) F[f[x]][i] = 1;
		}
		int now = 0;
		for(int i = 1;i <= n;i++)
		{
			int k = ++now;
			while(F[k][i] == 0 && k < tot) k++;
			if(F[k][i] == 0) 
			{
				zy++;
				now--;
				continue;	
			}
			if(k != now) Swap(F[now],F[k]);  
			for(int j = now+1;j <= tot;j++)
		 	 if(F[j][i] != 0)
		     {
		 		for(int k = 1;k <= n;k++)
		 		 F[j][k] ^= F[now][k];
		 	 }	
		}
		printf("Case #%d:\n%I64d\n",t,(ksm(2,zy)-1LL+MOD)%MOD);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值