【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; }