Codeforces Round 867 (Div. 3)
G1.Magic Triples (Easy Version)
题意:给定一个整数数组a,要求找出三元组(i,j,k)对应的 a [ i ] a[i] a[i], a [ j ] a[j] a[j], a [ k ] a[k] a[k] 维持 a [ j ] = b ∗ a [ i ] , a [ k ] = a [ j ] ∗ b a[j]=b*a[i],a[k]=a[j]*b a[j]=b∗a[i],a[k]=a[j]∗b的关系, 统计成对不同的三元组个数
思路:值域上界有mxm = 1e6,我们可以去枚举中间那个数x(桥梁),所以要去判断 x / b x/b x/b(b是x的因子)和 x ∗ b x*b x∗b是否存在( b ∗ x < = m x m b*x<= mxm b∗x<=mxm),考虑枚举 b(由于要保证 b ∗ x < = m x m b*x<=mxm b∗x<=mxm,所以我们只需要 O ( m x m ) O(\sqrt{mxm}) O(mxm),也就是b至多到1e3),总的复杂度 O ( n ∗ m x m ) O(n*\sqrt{mxm}) O(n∗mxm),足以通过此题,接下来考虑统计答案, 当b=1,也就是三个相同的数时容易得出结果,考虑b不为1,我们可以在 O ( x ) O(\sqrt{x}) O(x)的复杂度内求出一个数的全部因子,然后遍历这些因子,若当前因子 i t ∗ x > m x m it*x>mxm it∗x>mxm则已经无解,选择遍历x的下个因子it,若存在因子it使得 x / i t x/it x/it和 x ∗ i t x*it x∗it同时存在,则将三元对数加入答案
Code:
#include <bits/stdc++.h>
#define int long long
#define rep(i,a,n) for(int i=a; i<=n; i++)
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define pb push_back
using namespace std;
const int mxn=2e5+10, mxm=1e6;
int a[mxn];
vector<int> rs(int x){
vector<int> v;
for(int i=1; i*i<=x; i++){
if(x%i==0){
v.pb(i);
if(i!=x/i) v.pb(x/i);
}
}
sort(v.begin(),v.end());
return v;
}
void solve(){
auto get_same=[&](int x)->int{
return x*(x-1)*(x-2);
};
int n;
cin>>n;
map<int,int> Mp;
rep(i,1,n) cin>>a[i], Mp[a[i]]++;
int ans=0;
for(auto &[x,y]:Mp){
ans+=get_same(y);
auto v=rs(x);
for(auto it:v){
if(it==1) continue;//因子为1已经统计过
if(it*x>mxm) break;
if(Mp.count(x/it)&&Mp.count(x*it)){
ans+=y*Mp[x/it]*Mp[x*it];
}
}
}
cout<<ans<<'\n';
}
signed main(){
ios;
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}