2016中国大学生程序设计竞赛 - 网络选拔赛 1002 Zhu and 772002 hdu5833

本文介绍了一个数学问题,即如何计算由多个数值通过不同组合相乘得到的乘积为完全平方数的不同方式的数量,并提供了一种解决方案,即通过质因数分解和高斯消元的方法来解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

听说是白书原题。

直接按照质因子列异或方程组高斯消元即可

ans=2^自由元个数-1

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long mod=1000000007;
int prime[2001];
bool check[2001]; 
int tot;
inline void prepare()
{
     memset(check,false,sizeof(check));
     int i,j;
     for(i=2;i<=2000;i++)
     {
          if(!check[i])
          {
               tot++;
               prime[tot]=i;
          }
          for(j=1;j<=tot;j++)
          {
               if(i*prime[j]>2000)
                    break;
               check[i*prime[j]]=true;
          }
     }
}
int a[400][400],x[400],free_x[400];  
int equ,var,free_num;
long long b[301];
int Gauss()
{  
    int max_r,col,k;  
    free_num=0;  
    for(k=0,col=0;k<equ&&col<var;k++,col++)
	{  
        max_r=k;  
        for(int i=k+1;i<equ;i++)
		{  
            if(abs(a[i][col])>abs(a[max_r][col]))  
                max_r=i;  
        }  
        if(a[max_r][col]==0)
		{  
            k--;  
            free_x[free_num++]=col;  
            continue;  
        }  
        if(max_r!=k)
		{  
            for(int j=col;j<var+1;j++)  
                swap(a[k][j],a[max_r][j]);  
        }  
        for(int i=k+1;i<equ;i++)
		{  
            if(a[i][col]!=0)
			{  
                for(int j=col;j<var+1;j++)  
                    a[i][j]^=a[k][j];  
            }  
        }  
    }  
    for(int i=k;i<equ;i++)  
        if(a[i][col]!=0)  
            return -1;
    return var-k;
}
int main()
{
	prepare();
	int T,k=0;
	scanf("%d",&T);
	while(T>0)
	{
		T--;
		k++;
		int n;
		scanf("%d",&n);
		equ=tot;
		var=n;  
		memset(a,0,sizeof(a));  
  	    memset(x,0,sizeof(x));
  	    int i,j;
  	    for(i=1;i<=n;i++)
  	    	scanf("%I64d",&b[i]);
  	    for(i=1;i<=n;i++)
  	    {
  	    	long long t=b[i];
  	    	for(j=1;j<=tot;j++)
  	    	{
  	    		int sx=0;
  	    		while(t%prime[j]==0)
  	    		{
  	    			t/=prime[j];
  	    			sx++;
  	    		}
  	    		if(sx%2==1)
  	    			a[j-1][i-1]=1;
  	    	}
  	    }
  		int p=Gauss();
  		long long ans=1;
  		for(i=1;i<=p;i++)
  			ans=ans*(long long)2%mod;
		ans=(ans+mod-1)%mod;
  	    printf("Case #%d:\n%I64d\n",k,ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值