山东省第四届ACM省赛题——Square Number(平方数的性质)

题目描述
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.

输入
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).

输出
For each test case, you should output the answer of each case.
示例输入
1
5
1 2 3 4 12
示例输出
2

题意不难理解,主要是数据范围很大,暴力打表肯定不行。对于平方数n,它有一个性质是n一定等于奇数个质数相乘。比如36,它可以表示为2x18,3x12,4x9,其本质都是2x2x3x3。
所以对于题目中输入的每个数,要找出它的奇数的质数,比如3和12,两个数都有一个奇数的3,所以他们能相乘得到平方数,如果有3个以上奇个数的质数,取出任意两个都能组成平方数,因此这里要用到组合公式

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdio>
#include <set>
#include <vector>
#include <iomanip>
#include <stack>
#include <map>
#define MAXN 1000005
#define mod 9973
#define inf 0x3f3f3f3f
using namespace std;
int p[MAXN],a[MAXN],sq[MAXN],cnt;  //p保存素数,a判断当前数是否为素数,sq保存质数的平方数
int vis[MAXN]; //vis保存奇个数的质数
void Primer()
{
    int i,j, k;
    for(i=2;i<MAXN;++i)   //i从2开始遍历
    {
        if(a[i]==0)    //a[i]==0说明该i是素数
            p[cnt++]=i;   //cnt作为地址标志
        for(j=0;j<i&&(k=i*p[j])<MAXN;++j)   //j从0开始遍历,k作为有质数p[j]的合数
        {
            a[k]=1;    //合数设1
            if(i%p[j]==0)
                break;
        }
    }
}
int sum(int x)
{
    return x*(x-1)/2; //组合公式的化简
}
int main()
{
    ios::sync_with_stdio(false);
    cnt=0;
    Primer();
    int t,n,top=0,x;
    for(int i=0;i<cnt;++i)
    {
        sq[top++]=p[i]*p[i];
    }
    cin>>t;
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        cin>>n;
        for(int i=0;i<n;++i)
        {
            cin>>x;
            for(int j=0;sq[j]<=x;++j)
            {
                while(x%sq[j]==0)
                    x/=sq[j];
            }
            vis[x]++;
        }
        int ans=0;
        for(int i=0;i<MAXN;++i)
        {
            ans+=sum(vis[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值