给A,B,C,求他们的因子(a,b,c)的三元组的个数(a|A ,b|B,c|C,不考虑顺序)
A,B,C有重复因子很麻烦,所以考虑容斥
//1.因子总是和bitmask在一起
//要么是对因子用位压缩
//要么用二进制表示是a,b,c谁的因子,并且容斥
//2.m个不同的球有放回的取n个 = C(m + n - 1,n)
//3.__builtin_popcount(i) 返回i二进制中1的个数
题解:
http://codeforces.com/blog/entry/60642
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int cnt[8];
int use[8];
int f[maxn];//f[i]表示i的因子个数
ll C(int n,int k)
{
if(k == 1) return n;
else if(k == 2) return 1ll * n * (n - 1) / 2;
else if(k == 3) return 1ll * n * (n - 1) * (n - 2) / 6;
return -1;//
}
bool check(int i,int j,int k)
{
if(use[i] > __builtin_popcount(i)) return false;
if(use[j] > __builtin_popcount(j)) return false;
if(use[k] > __builtin_popcount(k)) return false;
return true;
}
int gcd(int a,int b){
return b == 0 ? a : gcd(b, a % b);
}
void init()
{
for (int i = 1; i < maxn; i ++) {
for (int j = i ; j < maxn; j += i) {
f[j] ++;
}
}
}
int main()
{
init();
int T;scanf("%d",&T);
while(T --){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int xy = gcd(x,y),xz = gcd(x,z),yz = gcd(y,z);
int xyz = gcd(xy,z);
cnt[1] = f[x] - f[xy] - f[xz] + f[xyz];//仅仅是x的因子,的个数
cnt[2] = f[y] - f[xy] - f[yz] + f[xyz];
cnt[4] = f[z] - f[xz] - f[yz] + f[xyz];//z
cnt[3] = f[xy] - f[xyz];//xy
cnt[5] = f[xz] - f[xyz];
cnt[6] = f[yz] - f[xyz];
cnt[7] = f[xyz];
ll ans = 0;
for(int i = 1;i < 8;i ++){
for(int j = i;j < 8;j ++){
for(int k = j;k < 8;k ++){
if((i | j | k) == 7){
ll tmp = 1;
memset(use,0,sizeof(use));
use[i] ++;use[j] ++;use[k] ++;
if(!check(i,j,k)) continue;
for(int a = 1;a < 8;a ++){
if(use[a]){
tmp *= C(cnt[a] + use[a] - 1,use[a]);
}
}
// printf("we choose %d %d %d %lld\n",i,j,k,tmp);
ans += tmp;
}
}
}
}
printf("%lld\n",ans);
}
return 0;
}