思路非常好,写博客总结一下。

给你n个数与m,让你找出所有的对数

首先对于我们 任意的  我们都可以将其分解为:

如果两个数相乘等于 x的k次方,那么两个数质因子分解后会有两种情况:

1.两个数分解后的质因子相同,且各质因子的幂次相加后为m的倍数

2.两个数分解后的质因子不同,那么不相同的质因子数的幂次绝对为m的倍数

所以我们首先对每一个 ai 进行质因子分解,用一个数将ai的质因子幂次%m后再乘起来。用map存一下。

在对现在的数进行质因子分解,求出他需要的数。

用map遍历一遍O(n)即可。

说明:不同质因子,一定幂次是m的倍数,取余幂次后已经消失了。

AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e9+7;
const int maxn=1e6+5;
const int INF=1e9+7;
using namespace std;
const double eps=1e-8;
ll n,m;
int prime[maxn];
int vis[maxn];
ll num[maxn];
ll cnt=0;
map<ll,ll>mp;
ll a[maxn],b[maxn];
void restart(){
    vis[1]=1;
    for(int i=2;i<1005;i++){
        if(!vis[i]){
            prime[++cnt]=i;
            for(int k=i*2;k<1005;k+=i)
                vis[k]=1;
        }
    }
}
ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a;
        b/=2;a=a*a;
    }
    return ans;
}

int main()
{
    restart();
    scanf("%lld%lld",&n,&m);mp.clear();
    for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
    ll res=0;
    for(int i=1;i<=n;i++){
        ll temp=num[i];
        ll now=1;
        for(int k=1;k<=cnt;k++){
            int cot=0;
            while(temp%prime[k]==0)
            {
                temp/=prime[k];
                cot++;
            }
            cot%=m;
            if(cot) now=now*qpow(prime[k],cot);
        }
        if(temp>1)  now*=temp;
        a[i]=now;
        mp[a[i]]++;
        b[i]=1;
        for(int k=1;k<=cnt;k++){
            int cot=0;
            while(now%prime[k]==0)
            {
                now/=prime[k];
                cot++;
            }
            cot%=m;
            if(cot) b[i]=b[i]*qpow(prime[k],m-cot);

        }
        if(now>1) b[i]*=qpow(now,m-1);
        if(b[i]==a[i]) res+=mp[b[i]]-1;
        else res+=mp[b[i]];
    }
    printf("%lld\n",res);
    return 0;
}

另外此题还有一种特别骚的办法...,map存一下 vector.

AC:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e9+7;
const int maxn=1e6+5;
const int INF=1e9+7;
using namespace std;
const double eps=1e-8;
ll n,m;
int prime[maxn];
int vis[maxn];
ll num[maxn];
ll cnt=0;
void restart(){
    vis[1]=1;
    for(int i=2;i<1005;i++){
        if(!vis[i]){
            prime[++cnt]=i;
            for(int k=i*2;k<1005;k+=i)
                vis[k]=1;
        }
    }
}
map<vector<pair<int,int>>,int>mp;
vector<pair<int,int>>v[100005];
vector<pair<int,int>>cop[100005];
int main()
{
    restart();mp.clear();
    scanf("%lld%lld",&n,&m);
    ll res=0;
    for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
    for(int i=1;i<=n;i++){
        ll temp=num[i];
        for(int k=1;k<=cnt;k++){
            int cot=0;
            while(temp%prime[k]==0){
                temp/=prime[k];
                cot++;
            }
            cot%=m;
            if(cot){
                v[i].push_back(make_pair(prime[k],cot));
                cop[i].push_back(make_pair(prime[k],m-cot));
            }
        }
        if(temp>1){
            v[i].push_back(make_pair(temp,1));
            cop[i].push_back(make_pair(temp,m-1));
        }
        res+=mp[cop[i]];
        mp[v[i]]++;
    }
    printf("%lld\n",res);
    return 0;
}
/***
6 4
4 4 16 1 4 4
***/

总结:

别遇到对数就去二分了...多动脑子.

根号下分解质因数需要特判剩余数>1