Zhu and 772002

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
 

这题就是先转化成异或方程组,再用高斯消元求解矩阵的秩,然后就可以求出个数了.

对我这个初学者来说,我觉得自己上面这波逼装的,可以给满分。

看了别人的代码,感觉本题的思路主要是,先找出0~2000中所有的质数,然后依次读取每一个数,将其分解为很多个质数乘积的形式,并存入数组(要注意的是那个保存数据的数组每一行代表的是某一个质数在各个读取的书中有几个,而每一列代表一个数可以被分成多少个质数,每个质数有多少个),同时只需要0和1来代表个数就行了,因为偶数个的可以直接约去,这时我们视其为一个方程组,要使每一行的解为0,所以根据线性代数里面教的,就依次把每一行的第一个化为1,化完之后,会有多个数字并不在每一行的开头,那么这些数字就是无法确定的点,有两种情况,因为根据后面的点的选取就可以确定每一行开头那点的数值,所以2的n次方(n为无法确定的点的个数),就是所有可能的情况,又因为我们要排除所有点都没取的情况,所以说要再减去1,那就是结果了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int prime[500];
bool number[2000+10];
int shuzu[500][310];
int num=0;
__int64 a[310];

void init()
{
	memset(number,true,sizeof(number));
	int i,j;
	for(i=2;i<=2000;i++)
	{
		if(number[i])
		{
			prime[num++]=i;
			for(j=i;j<=2000;j=j+i)
			{
				number[j]=false;
			}
		}
	}
}

void trans(int i)
{
	__int64 pre=a[i];
	int j;
	for(j=0;j<num;j++)
	{
		while((pre%prime[j]==0))
		{
			shuzu[j][i]^=1;
			pre=pre/prime[j];
		}
		if(pre==0)
			break;
	}
}

__int64 pow(int x,int n)
{
	__int64 temp(x),res(1);
	while(n)
	{
		if(n&1) 
		{
			res =(res*temp)%1000000007;
		}
		temp =(temp*temp)%1000000007;
	n>>=1;
	}
	return res;
}

__int64 solve(int num,int n)
{
	int i=0,j=0,k,r,u;
	while(i<num&&j<n)
	{
		for(k=i;k<num;k++)
		{
			if(shuzu[k][j])
			{
				r=k;
				break;
			}
		}
		if(shuzu[k][j])
		{
			if(r!=i)
			{
				for(u=0;u<n;u++)
					swap(shuzu[i][u],shuzu[r][u]);
			}
			for(k=r+1;k<num;k++)
			{
				if(shuzu[k][j])
				{
					for(u=j;u<n;u++)
						shuzu[k][u]^=shuzu[i][u];
				}
			}
		i++;
		}
		j++;
	}
	return pow(2,n-i)-1;
}

int main()
{
	int t;
	scanf("%d",&t);
	int icase;
	init();
	for(icase=1;icase<=t;icase++)
	{
		memset(shuzu,0,sizeof(shuzu));
		int n;
		scanf("%d",&n);
		int i;
		for(i=0;i<n;i++)
		{
			scanf("%I64d",&a[i]);
			trans(i);
		}
		__int64 ans=solve(num,n);
		printf("Case #%d:\n",icase);
		printf("%I64d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值