暴力
由于值的范围很小($ leq 2*10^6$),所以用一个cnt数组统计每个值有多少个数,然后从小到大,统计每个数的倍数即可。
根据调和数?的神奇性质= =这样是$O(nlogn)$的……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************************** 2 Problem: 4146 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:4644 ms 7 Memory:9084 kb 8 ****************************************************************/ 9 10 //BZOJ 4146 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=2e6+10,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,c[N]; 32 int main(){ 33 #ifndef ONLINE_JUDGE 34 freopen("4146.in","r",stdin); 35 freopen("4146.out","w",stdout); 36 #endif 37 n=getint(); 38 int mx=0; 39 F(i,1,n){ 40 int x=getint(); 41 c[x]++; 42 mx=max(mx,x); 43 } 44 LL ans=0; 45 F(i,1,mx) if (c[i]){ 46 ans+=(LL)c[i]*(c[i]-1); 47 for(int j=i+i;j<=mx;j+=i) ans+=(LL)c[i]*c[j]; 48 } 49 printf("%lld ",ans); 50 return 0; 51 } 52
4146: [AMPPZ2014]Divisors
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 12 Solved: 6
[Submit][Status][Discuss]
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)。