[ABC342D] Square Pair 题解

【题目描述】

给定一个长度为 \(N\) 的非负整数序列 \(A=\left(A_1,\cdots,A_n\right)\)。求满足以下条件的整数对 \(\left(i,j\right)\) 的数量。

  • \(1\le i < j \le n\)
  • \(A_iA_j\) 是平方数

其中,如果某个非负整数 \(a\) 可以用某个非负整数 \(d\) 表示为 \(a=d^2\),那么称 \(a\) 是平方数。

【思路】

首先发现,一个数是平方数,当且仅当这个数的所有质因数的次数都是偶数。

因为 \(a\) 是平方数,考虑 \(a=d^2\)\(d\) 的分解为 \(d={p_1}^{q_1} {p_2}^{q_2} \cdots {p_n}^{q_n}\)

\(a\) 的分解为 \(a={p_1}^{2q_1} {p_2}^{2q_2} \cdots {p_n}^{2q_n}\)​​。

所以 \(a\)​ 的所有质因数的次数都是偶数。

那么,两个数 \(A,B\)​ 的积是平方数,说明了这么个事:

  • \(A,B\) 两数都是平方数(每个质因子次数都是偶数):那做完乘法之后还是平方数(质因子次数还是偶数)

  • \(A,B\)​ 两个数,每个数都有次数是奇数的质因子,这些质因子是相同的,所以在做完乘法之后消去了。

举个例子:

  • 两个数都是平方数,乘法之后还是平方数:

    \(\begin{array}{c} \ \ \ \ \ \ \ \ A=2^2 \times 3^6 \times 7^4 \\ \ \ \ \ \ \ \ \ B=2^2 \times 3^2 \times 7^2 \\ A\times B=2^4 \times 3^8 \times 7^6 \end{array}\)

  • 两个数都有次数是奇数的质因子,在做完乘法之后消去了:

    \(\begin{array}{c} \ \ \ \ \ \ \ \ A=2^2 \times 3^3 \times 7^1 \\ \ \ \ \ \ \ \ \ B=2^2 \times 3^3 \times 7^5 \\ A\times B=2^4 \times 3^6 \times 7^6 \end{array}\)

所以我们可以得出一个普遍规律:

对于两个数,他们次数是奇数的质因子相同,那么两个数在做完乘法之后就是一个平方数。

但是这题有个坑,\(A_i\) 可能是 \(0\),所以要特判一下:

  • \(0\times0=0\) 是一个平方数
  • \(0\) 乘以任何数都是 \(0\)

于是这道题就4发罚时愉快的做完了。

嗯。

【Code】

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,a[200005],Zero,ans;
map<int,int>s;

//筛质数,加速找质因子
int Primes[200005],tot;
bool vis[200005];
void Search_primes(int n){
	memset(vis,true,sizeof(vis));
	vis[0]=vis[1]=0;
	for(int i=2;i<=n;i++){
		if(vis[i]) Primes[++tot]=i;
		for(int j=1;j<=tot and i*Primes[j]<=n;j++){
			vis[i*Primes[j]]=0;
			if(i%Primes[j]==0) break;
		}
	}
}

//计算一个数次数为奇数的质因子
int Bu(int x){
    if(x==0) return 0;
    int res=1,X=x;
    for(int i=1;i<=tot;i++){
        if(Primes[i]*Primes[i]>X) break;
        if(x%Primes[i]==0){
            int sum=0;
            while(x%Primes[i]==0) x/=Primes[i],sum++;
            if(sum%2==1) res*=Primes[i];
        }
    }
    if(x>1) res*=x;
    return res;
}

signed main()
{
    scanf("%lld",&n);
    Search_primes(n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        s[Bu(a[i])]++;
        if(a[i]==0) Zero++;
    }
    for(auto it:s){
        int sum=it.second;
        ans+=sum*(sum-1)/2;
    }
    printf("%lld",ans+Zero*(n-Zero));
    return 0;
}

【后记】

祝大家上分。

由于手速不够快没交上题解。。。

posted @ 2024-02-28 19:50  Sundar_2022  阅读(57)  评论(0编辑  收藏  举报