6015. 统计可以被 K 整除的下标对数目(数论&计数)

思路1

a x ( m o d k ) = 0 ax\pmod{k} =0 ax(modk)=0 求满足条件最小的 x x x。

显然将 a , k a,k a,k的所有公共因子去掉后的 k k k就是答案。

所以 x = k g c d ( a , k ) x=\dfrac{k}{gcd(a,k)} x=gcd(a,k)k。

而所有 x x x的倍数 ( x , 2 x , 3 x , …   ) (x,2x,3x,\dots) (x,2x,3x,…)都满足答案。

而这个我们可以进行类似线性筛进行预处理。

时间复杂度: O ( n l o g l o g n + n ) O(nloglogn+n) O(nloglogn+n)

因为题目要求 ( i , j ) , i < j (i,j),i<j (i,j),i<j,而我们计算的时候 i < j i<j i<j算了两次, i = j i=j i=j算了一次。所以最后只需要特判一遍 a i × a i ( m o d k ) = 0 a_i\times a_i\pmod{k} =0 ai×ai(modk)=0则减1。

class Solution {
public:
long long coutPairs(vector<int>& a, int k) {
int n = a.size();
vector<int>b(1e5+1);
for(int x:a) b[x]++;
for(int i=1;i<=1e5;i++)
for(int j=i<<1;j<=1e5;j+=i) b[i]+=b[j];
long long ans = 0;
for(int x:a){
ans+=b[k/__gcd(x,k)];
if(1LL*x*x % k ==0) ans--;
}
return ans>>1;
}
};

思路2

我们按照 g c d ( x , k ) gcd(x,k) gcd(x,k) 对 x x x分组。

当两组所需要的数相乘是 k k k的倍数时说明满足情况。因为他们非需要的数都有了。

1 0 5 10^5 105的因子最多 128 128 128个。

时间复杂度: O ( 12 8 2 + n l o g k ) O(128^2+nlogk) O(1282+nlogk)

class Solution {
public:
long long coutPairs(vector<int>& a, int k) {
int n = a.size();
unordered_map<int,int>mp;
long long ans = 0;
for(int x:a) mp[__gcd(x,k)]++;
for(auto [x,y]:mp){
for(auto [u,v]:mp){
if((1LL * x * u % k == 0)){
if(x==u) ans+=1LL*y*(y-1)>>1;
else if(x<u) ans+=1LL*y*v;
}
}
}
return ans;
}
};