标签:long int order == rac isp ret pac clu
给定数组\(a(\left| a \right|\leq 10^5)\)和整数\(k(2\leq k \leq 100)\),问满足一下条件的二元组\(<i,j>\)的数目:
其实就是求
\[
\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;
}
标签:long int order == rac isp ret pac clu
原文地址:https://www.cnblogs.com/zengzk/p/11747124.html