D. Counting Rhyme
题解
求有多少 \(pair\) 的 \(gcd\) 是 \(a_k\) 的倍数
\(\to\) 对于 \(a_k\) 求有多少 \(a_i,a_j\) 的 \(gcd\) 是其倍数(降次)
\(\to\) 遍历 \(k\in[1,n]\) 求对于每个 \(k\),有多少 \(a_i,a_j\) 使得 \(gcd(a_i,a_j)==k\) (去重)
判断累积答案,注意去重
时间复杂度 \(n·logn\)
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[1000005]={0};
ll cnt[1000005]={0};
inline void read(ll &x) {
x = 0;
ll flag = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')flag = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
x *= flag;
}
inline void write(ll x)
{
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int main()
{
ll t;
read(t);
while(t--)
{
ll n;
read(n);
for(ll i=1;i<=n;i++)
{
ll x;
read(x);
cnt[x]++;
}
for(ll i=n;i>=1;i--)
{
ll sum=0;
for(ll j=i;j<=n;j+=i)
{
sum+=cnt[j];
}
dp[i]=sum*(sum-1)/2;
for(ll j=i+i;j<=n;j+=i) dp[i]-=dp[j];
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
if(cnt[i])
{
for(ll j=i;j<=n;j+=i)
{
ans+=dp[j];
dp[j]=0;
}
}
dp[i]=0;
cnt[i]=0;
}
write(n*(n-1)/2-ans);
putchar('\n');
}
return 0;
}

浙公网安备 33010602011771号