思路:这一道题是一道数论的题, 主要还是算数基本定理理解的不透彻, 接下来我们仔细分析如何去解决这道题:
首先看数据范围,
a
[
i
]
a[i]
a[i] 的取值范围是
100000
100000
100000 , 我们可以知道100000 的质因数的个数大约是
n
ln
n
n \over\ln^n
lnnn 个, 对于在此范围内的某一个数来说如果我们想要去使得此数分解质因数之后不同的质因数的个数最多的话一定是从2开始, 但由于 2 * 3 * 5 * 7 * 11 * 13 * 17 = 510510 ,已经50万了, 所以如果我们根据算数基本定理分解这个数之后最多的项数是6个。
a
l
×
a
r
=
x
k
a_l×a_r=x^k
al×ar=xk , 这个条件告诉我们什么 ? 就是
a
l
×
a
r
a_l×a_r
al×ar 能够开k次方就行, 但由于n的范围是十万,暴力枚举的话一定超时, 我们可以这样想:
对于每一个a[j] 来说,利用哈希表的思想查询前面有几个数满足条件:但如何去实现前面的映射呢?
我们对a[j] 来在分解的时候我们都要将每一个质因子的次幂对k进行一个取模, 这样写的好处就是消除了k的倍数的影响,更加容易进行一个判断, 这个时候我们只需要判断次幂不为零的质因子的个数和它对应的那个数应该是多少就行了。 中间我们要利用一个cnt[] 数组去记录该数前面的每一个经过处理后的数的个数。然后把这个数记录一下就行了。
需要注意的点:
1.我们在求每一个数的对应的那个数的时候, 如果发现那个数一旦大于10万就直接返回0就行了。 要不然会发生段错误
2.统计的sum要开long long ,不然会爆int .
AC代码:
#include <iostream>
using namespace std ;
const int N = 100010 ;
typedef long long LL ;
LL cnt[N] ;
LL pow1(int a , int b )
{
LL res = 1 ;
while(b -- )
{
res *= a ;
if(res > N )
{
res = 0 ;
break ;
}
}
return res ;
}
int main()
{
int n , k ;
LL sum = 0 ;
cin >> n >> k ;
while(n -- )
{
int x ;
cin >> x ;
LL res = 1 , p = 1 ;
for(int i = 2 ; i <= x / i ; i ++ )
{
if(x % i == 0 )
{
int s = 0 ;
while(x % i == 0 )
{
s ++ ;
x /= i ;
}
s %= k ;
if(s)
{
p *= pow1(i , s ) ;
res *= pow1(i , k - s ) ;
}
}
}
if(x != 1 )
{
p *= x ;
res *= pow1(x , k - 1) ;
}
if(res > N ) res = 0 ; // 这个地方相当于判断下标是否合法。
sum += cnt[res] ;
cnt[p] ++ ;
}
cout << sum << endl ;
return 0 ;
}