杂例输出acwing

题意
在这里插入图片描述

思路:这一道题是一道数论的题, 主要还是算数基本定理理解的不透彻, 接下来我们仔细分析如何去解决这道题:
首先看数据范围, 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 ; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值