轉載請注明出處: http://www.cnblogs.com/gufeiyang
題意: 給出n個數(n<100000), 每個數都不大於100000,數字不會有重復。現在隨意抽出3個,問三個彼此互質 或者 三個彼此不互質的數目有多少。
思路: 這道題的原型是同色三角形, 可能現場很多隊伍都知道這個模型, 所以這道題當時過的隊伍還是挺多的。
這道題反着想,就是三個數中只有一對互質 或者只有兩對互質的個數。研究后發現 對於每個數字求出與其不互質的個數k 那么 sum ( k*(n-1-k) )/2 就是相反的數目, 所以最終的答案就是 C(n,3) - sum ( k*(n-1-k) )/2。現在依然存在一個問題就是如何求出每個數的不互質數的個數,這個其實用容斥原理。 對於數字 a ,求出a的所有素因子, 然后枚舉素因子可以構成的所有數字(構成數的過程中素因子用的個數不能超過1) w,求出原先數組中能被w整除的個數。 如果w的素因子個數為奇數就加, 偶數就減。 這就是容斥的過程。
現在還是存在一個問題, 如何快速算出原先數組中能整出w的個數。 首先對原先數據中的每個數字a, 求出所有的素因子, 然后枚舉素因子可以構成的所有數字(構成數的過程中素因子用的個數不能超過1),對於每一個枚舉的數統計加1. 這樣就能提前預處理出來。
算法的整體復雜度為 O(n*64*6);
AC代碼:
#include <cstdio> #include <cstring> #include <queue> #include <string> #include <iostream>
using namespace std; const int N = 200500; typedef long long LL; int p[N]; int num; bool in[N]; int a[N]; int n; int nn[N]; void get_prime() { num = 0; for(int i=2; i<N; i++) { if(!in[i]) { p[num++] = i; for(int j=i; j<N; j+=i) { in[j] = true; } } } } void init() { memset(nn, 0, sizeof(nn)); int cnt = 0; int ele[100]; scanf("%d", &n); int temp = 0; for(int i=0; i<n; i++) { scanf("%d", &a[i]); temp = a[i]; cnt = 0; for(int j=0; p[j]*p[j] <= temp; j++) { if(temp % p[j] == 0) { ele[cnt++] = p[j]; while(temp%p[j] == 0) temp /= p[j]; } } if(temp != 1) { ele[cnt++] = temp; } for(int j=1; j<(1<<cnt); j++) { temp = 1; for(int k=0; k<cnt; k++) { if( (1<<k) & j ) { temp *= ele[k]; } } nn[temp]++; } } } void solve() { LL ans = n; LL ss = 0; int temp; ans = ans*(n-1)*(n-2)/6; for(int i=0; i<n; i++) { int cnt = 0; int ele[100]; temp = a[i]; cnt = 0; for(int j=0; p[j]*p[j] <= temp; j++) { if(temp % p[j] == 0) { ele[cnt++] = p[j]; while(temp%p[j] == 0) temp /= p[j]; } } if(temp != 1) { ele[cnt++] = temp; } LL ret = 0; for(int j=1; j<(1<<cnt); j++) { temp = 1; int hh = 0; for(int k=0; k<cnt; k++) { if( (1<<k) & j ) { temp *= ele[k]; hh++; } } if(hh%2 == 1) ret += nn[temp]; else ret -= nn[temp]; } if(ret == 0) continue; ss = ss + (ret-1)*(n-ret); // cout<<i<<" "<<ret<<" "<<ss<<endl;
} cout<<ans - ss/2<<endl; } int main() { get_prime(); int t; scanf("%d", &t); while(t--) { init(); solve(); } return 0; }

