Codeforces1247D 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;
}
posted @ 2019-10-27 12:11  _Backl1ght  阅读(509)  评论(0编辑  收藏  举报