【BZOJ4146】[AMPPZ2014]Divisors
Description
给定一个序列a[1],a[2],...,a[n]。求满足i!=j且a[i]|a[j]的二元组(i,j)的个数。
Input
第一行包含一个正整数n(1<=n<=2000000),表示序列长度。
第二行包含n个正整数,依次表示a[1],a[2],...,a[n](1<=a[i]<=2000000)。
Output
一个整数,即满足条件的二元组的个数。
Sample Input
5
2 4 5 2 6
2 4 5 2 6
Sample Output
6
HINT
满足条件的6组分别为(1,2),(1,4),(1,5),(4,1),(4,2),(4,5)。
题解:一开始想把每个数的所有约数都列出来,时间复杂度理论O(n ln n)然而TLE
好吧,对于每个数,直接枚举有多少个数是它的倍数,然后统计一下就好了
时间复杂度:相当于是n以内所有数的约数个数和,是O(n ln n)级别的(不会证,但用暴力枚举去逼近的话真的是这个级别的)
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=2000010;
int p[maxn],maxx,tot,n;
long long v[maxn],ans;
int rd()
{
int ret=0; char gc=getchar();
while(gc<'0'||gc>'9') gc=getchar();
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret;
}
int main()
{
n=rd();
int i,j;
for(i=1;i<=n;i++) p[i]=rd(),v[p[i]]++,maxx=max(maxx,p[i]);
for(i=1;i<=n;i++)
{
ans+=(v[i]-1)*v[i];
for(j=i+i;j<=maxx;j+=i) ans+=v[i]*v[j];
}
printf("%lld",ans);
return 0;
}