http://acm.hdu.edu.cn/showproblem.php?pid=5072
现场赛和队友想了3个小时,最后发现想跑偏了。感觉好可惜的一道题,要是知道这个模型....就能够轻松的拿银了啊。
。
。
题意不再赘述,就是求同色三角形的个数。总的三角形的个数是C(n,3),仅仅需减去不同色的三角形就可以。对于每一个点(数),与它互质的连红边,不互质的连蓝边,那么对于该点不同色三角形个数为蓝边数*红边数/2,由于同一个三角形被计算了两次。
那么同色三角形个数为C(n,3) - ∑蓝边数*红边数/2。
我们仅仅需求出蓝边数就能得知红边数。怎么求与该数不互质的数的个数?首先对原来的数质因子分解,把这些质因子的全部组合枚举出来,每一个质因子最多使用一次,得到若干个质因子的组合为ansNum,使用容斥原理,观察ansNum的质因子的个数。若是奇数就加上全部能被ansNum整数的数的个数。否则就减去。这样求出蓝边数。红边数也就已知了。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <bitset> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL __int64 //#define LL long long #define eps 1e-9 #define PI acos(-1.0) using namespace std; const LL INF = 1<<30; const int maxn = 100010; int test; LL n; int a[maxn],num[maxn]; int prime[maxn]; bool flag[maxn]; int fact[maxn][20]; int coun[maxn]; void getPrime() { memset(flag,0,sizeof(flag)); flag[1] = true; prime[0] = 0; for(int i = 2; i < maxn; i++) { if(flag[i] == false) prime[++prime[0]] = i; for(int j = 1; j <= prime[0]&&i*prime[j] < maxn; j++) { flag[prime[j]*i] = true; if(i%prime[j] == 0) break; } } } void getFact(int dig, int pos) { int tmp = dig; for(int i = 1; i <= prime[0] && prime[i]*prime[i] <= tmp; i++) { if(tmp % prime[i] == 0) { fact[pos][coun[pos]++] = prime[i]; while(tmp % prime[i] == 0) tmp /= prime[i]; } if(tmp == 1) break; } if(tmp > 1) fact[pos][coun[pos]++] = tmp; } void init() { for(int i = 2; i <= 100000; i++) { for(int j = i+i; j <= 100000; j += i) num[i] += num[j]; } } int main() { getPrime(); scanf("%d",&test); while(test--) { memset(num,0,sizeof(num)); scanf("%I64d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); num[a[i]]++; } init(); memset(coun,0,sizeof(coun)); LL ans = 0; for(int i = 1; i <= n; i++) { LL res = 0; getFact(a[i], i); for(int j = 1; j < (1<<coun[i]); j++) { LL ansNum = 1; int cnt = 0; for(int k = 0; k < coun[i]; k++) { if(j & (1<<k) ) { ansNum *= fact[i][k]; cnt++; } } if(cnt & 1) res += (num[ansNum]-1); else res -= (num[ansNum]-1); } ans += (n-1-res)*res; } ans = n*(n-1)*(n-2)/6 - ans/2; //注意n为LL printf("%I64d ",ans); } return 0; }