山東省第六屆ACM大學生程式設計競賽-Square Number(完全平方數)

kewlgrl發表於2016-05-23

Square Number

Time Limit: 1000ms   Memory limit: 65536K  有疑問?點這裡^_^

題目描述

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

提示

 

來源

 

示例程式


題目意思:

有一些資料,兩個為一組,兩兩相乘為完全平方數的有多少組?


解題思路:

一個完全平方數可以分解成偶數個素數相乘。

由↑這個思路,我們可以先打一個素數表,然後遍歷素數表。

設一個數m為使得m與這個數相乘是一個完全平方數的數,算出這個數能被素數prm[j]整除的次數,如果是奇數次就乘到m上;把遍歷最後剩下的數也乘到m上去。


這個素數表很重要哇,選不好效率高的素數表就要TLE啦~

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000010
int a[MAXN],vis[MAXN];
long long ans;
bool is[MAXN];//用來求素數
int prm[MAXN];//用來儲存素數
int totleprm=0;//記錄素數總個數

void getprm()//打素數表
{
    int i,j,m;
    memset(is,0,sizeof(is));
    is[1]=1;
    m=sqrt(MAXN);
    for(i=2; i<=m; i++)
        if(!is[i])
            for(j=i*i; j<MAXN; j+=i)
                is[j] = 1;
    for(i=2; i<MAXN; i++)
        if(!is[i])
            prm[totleprm++]=i;
}

int main()
{
    int t;
    getprm();//素數打表
    cin>>t;
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        int n,i,j;
        ans=0;
        cin>>n;
        for(i=0; i<n; i++)
        {
            cin>>a[i];//輸入資料
            int m=1;//儲存應當再乘的數
            for(j=0; j<totleprm; j++)//遍歷素數表
            {
                int acnt=0;//儲存數a[i]能被素數prm[j]整除的次數
                while(a[i]%prm[j] == 0)
                {
                    a[i]/= prm[j];
                    ++acnt;
                }
                if(acnt%2) m*=prm[j];//如果整除的次數為奇數,就把這個素數乘上
                if(!is[a[i]]||a[i]==1)//a[i]==1這句不加會超時……
                {
                    m*=a[i];//如果除到最後是個素數,把剩的這個數也乘上
                    break;
                }
            }
            ans+=vis[m];
            ++vis[m];//記錄應當再乘的數的出現次數,觀察在其整個資料序列中出現的次數
        }
        cout<<ans<<endl;
    }
    return 0;
}
/*
1
5
1 2 3 4 12
*/

相關文章