CF1247D Power Products 暴力+优化

题意

给定数组\(a(\left| a \right|\leq 10^5)\)和整数\(k(2\leq k \leq 100)\),问满足一下条件的二元组\(<i,j>\)的数目:

  • \(1 \leq i <j\leq n\)
  • \(\exist x,a_i \cdot \ a_j=x^k\)

解题思路

其实就是求
\[ \sum_{i=1}^{n-1}\sum_{j=i+1}^n \left [ a_i \cdot \ a_j=x^k\right] \]
\(x\)提出来,式子变为
\[ \sum_{i=1}^n\sum_{x=1}^{x^k\leq10^{10}} cnt_{x^k/a_i},其中cnt_j表示当前j出现的次数 \]
这样求的复杂度是\(O(n10^{\frac{10}{k}})\),在\(k \geq 3\)的时候是足够优秀的,所以需要特判一下\(k=2\)的情况。

如果将整数看成多个素数的乘积,即\(n=\Pi_i p_i^{x_i}\)

那么两个整数相乘的结果是平方数\(\Leftrightarrow\)对应素数的幂次应该同奇偶

所以用一个bitset表示,用map记录一下,这个问题就解决了

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn=1e5+5;
const int cntp=1e4+5; //1e5内素数的个数,一开始bitset开1e5的大小MLE了
unordered_map<bitset<cntp>,int>mp;
int n,m,k,a[maxn],cnt[maxn],p[maxn],tot;
ll ans,x[maxn];
inline ll qp(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}
inline bool check(int x){
    for(int i=2;i<=sqrt(x);i++){
        if(x%i==0)return false;
    }
    return true;
}
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    
    if(k==2){
        
        for(int i=2;i<maxn;i++)if(check(i))p[++tot]=i;
        
        bitset<cntp>b;
        for(int i=1;i<=n;i++){
            b.reset(); b.set(0);
            ll tmp=a[i];
            int cnt=0;
            for(int j=1;j<=tot;j++){
                while(tmp%p[j]==0){++cnt; tmp/=p[j];}
                if(cnt&1)b.set(j);
                cnt=0;
                if(tmp==1)break;
            }
            ans+=mp[b];
            mp[b]++;
        }
    }
    else{
        for(ll i=1;;i++){
            x[i]=qp(i,k);
            if(x[i]>=1e10){
                m=i;
                break;  
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i]>x[j])continue;
                if(x[j]%a[i]==0 && x[j]/a[i]<maxn){
                    ans+=cnt[x[j]/a[i]];
                }
            }
            ++cnt[a[i]];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zengzk/p/11747124.html
今日推荐