hdu 5833 Zhu and 772002 2016中国大学生程序设计竞赛 - 网络选拔赛1002 [质因子分解+高斯消元]【数论】

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5833
——————————-.
Zhu and 772002

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 446 Accepted Submission(s): 147

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(1≤n≤300),next line there are n numbers a1,a2,…,an,(1≤ai≤1018).

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

Author
UESTC

Source
2016中国大学生程序设计竞赛 - 网络选拔赛

———————————————-.

题目大意: 就是有n这么长的序列 然后从中选至少一个数 让这些数的乘积为完全平方数 问有多少种选法

题目分析:
首先注意题目说的 a[i]的最大质因子不会超过2000 这也是在提示你要质因子分解 分解就简单处理一下分解就行了 怎么分都行
这里首先想到的就应该是算数基本定理
A=p1^a1*p2^a2*p3^a3*…*pn^an (pn是质数)
然后分解的时候怎么怎么存储数据?,怎么操作呢?
首先要想这个问题
几个数相乘的结果如果是完全平方数 有什么特点呢?
说白了就是开方后能得到一个整数
比如说B=a1*a2; B,a1,a2都为整数 且a1==a2
那么a1和a2 他们质因子分解后是完全一样的
那么B的算是基本定理展开就等于a1的算是基本定理展开乘上a2的算是基本定理展开
那么可以肯定的是B的算是基本定理展开 an一定是偶数的 所以就能拆成两个a1 a2
那么反过来说只要B的算是基本定理展开 an都是偶数 就一定是完全平方数
那么在判断的时候就只要判断an的值的奇偶性就可以了
于是我们就开了这样的数组factor[n+10][333] (2000以内的质数只有303个)
把每个数转化为了一个2进制数
我们可以把题目转化成求n个数中的k个数数异或为0的情况数。使用x1—xn表示最终第i堆石子到底取不取(1取,0不取),将每堆石子数画成2进制的形式,列成303个方程来求自由变元数,最后由于自由变元能取1、0两种状态
然后直接高斯消元就可以了
最后的结果就是 2^(自由元)-1

注: 最终结果减去的那个一 减去的是1个都不选则情况下的0

附本题代码
———————————–.


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

const int MOD = 1000000007;

#define weishu k


int prime[50000];
int Is_or[20100];
int k;
void Prime()
{
    int n=2001;
    k=0;
    memset(Is_or,1,sizeof(Is_or));
    Is_or[0]=Is_or[1]=0;
    for(int i=2; i<n; i++)
    {
        if(Is_or[i])
        {
            prime[k++]=i;
            for(int j=i+i; j<n; j+=i)
            {
                Is_or[j]=0;
            }
        }
    }
    return ;
}


LL a[333];

LL  g[333][333];

int Gauss(int n)
{
    int i, j, r, c, cnt;
    for (c = cnt = 0; c < n; c++)
    {
        for (r = cnt; r < weishu; r++)
        {
            if (g[r][c])
                break;
        }
        if (r < weishu)
        {
            if (r != cnt)
            {
                for (i = 0; i < n; i++)
                {
                    g[r][i]^=g[cnt][i];
                    g[cnt][i]^=g[r][i];
                    g[r][i]^=g[cnt][i];
                }
            }
            for (i = cnt + 1; i < weishu; i++)
            {
                if (g[i][c])
                {
                    for (j = 0; j < n; j++)
                        g[i][j] ^= g[cnt][j];
                }
            }
            cnt++;
        }
    }
    return n - cnt;
}
LL qmod (LL a,LL b)
{
    LL res = 1;
    while(b)
    {
        if(b&1)  res=(res*a)%MOD;
        b >>= 1;
        a=(a*a)%MOD;
    }
    return res;
}
int main()
{
    Prime();
    int c,p=0;
    int n, i, j;

    scanf("%d", &c);
    while (c--)
    {
        int fuck = 0;
        scanf("%d", &n);
        memset(g,0,sizeof(g));
        LL temp;
        for(int i=0; i<n; i++)
        {
            scanf("%I64d",&a[i]);
            temp=a[i];
            for(int j=0; j<k; j++)
            {
                if(temp<prime[j]) break;
                while(temp%prime[j]==0)
                {
                    temp/=prime[j];
                    g[j][i]++;
                }
                g[j][i]%=2;
            }
        }
        LL ans, vary;
        vary = Gauss(n);
        printf("Case #%d:\n",++p);
        ans = qmod(2,vary);
        printf("%I64d\n",(ans-1)%MOD);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值