SDUT3258Square Number(2015年山东省第六届ACM大学生程序设计竞赛)

Square Number

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description

In mathematics, a square number is an integer that is the square of an integer. In other words, it is the product of some integer with itself. For example, 9 is a square number, since it can be written as 3 * 3.

Given an array of distinct integers (a1, a2, ..., an), you need to find the number of pairs (ai, aj) that satisfy (ai * aj) is a square number.

Input

The first line of the input contains an integer T (1 ≤ T ≤ 20) which means the number of test cases.

Then T lines follow, each line starts with a number N (1 ≤ N ≤ 100000), then N integers followed (all the integers are between 1 and 1000000).

Output

For each test case, you should output the answer of each case.

Example Input
1   
5   
1 2 3 4 12
Example Output
2


题意:

给出n个数,算出有多少对数,两两相乘为平方数。


分析:

一个数为偶数,那么它的每个质因子个数肯定也是偶数个。现在的问题就是,如果有一个数p,把它的个数为偶数的质因子去掉之后就剩下了个数为奇数的质因子,对数q做同样的操作,那么p与q必须有相同的质因子,且每个质因子个数和为偶数。


具体的做法就是把1000000以内,所有质数的平方都筛选出来,然后将读入的数对质数的平方进行取模,模出来的结果肯定就是所有个数为1的质因子的乘积,对相应的乘积做好记录,每个读入的数都进行这样操作,就可以与前面记录过的配对。具体实现请看代码。


总结:

对于这道题,一开始想到的还是存每个数的质因子,然后进行用map、set搞搞,还是

想不到更高效的办法。硬伤.....

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1e6+10;
int prim[1005], it[1005], vis[maxn];
int amount = 0;
void init()
{
    for(int i = 2; i <= 1000; i++)//筛选素数
        if(prim[i] == 0)
            for(int j = i*i; j <= 1000; j += i)
                prim[j] = 1;
    int cou = 0;
    for(int i = 2; i <= 1000; i++)//素数平方打表
        if(prim[i] == 0)
            it[amount++] = i * i;
}
int main()
{
    int n, ans, t, T;
    init();
    cin >> T;
    while(T--)
    {
        ans = 0;
        cin >> n;
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i < n; i++)
        {
            cin >> t;
            for(int j = 0; j < amount; j++)
                if(t % it[j] == 0)
                    while(t % it[j] == 0)
                        t /= it[j];
            ans += vis[t];//统计状态
            vis[t]++;
        }
        cout << ans << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值