Pave the Parallelepiped
You are given a rectangular parallelepiped with sides of positive integer lengths A, B and C
.
Find the number of different groups of three integers (a
, b, c) such that 1≤a≤b≤c and parallelepiped A×B×C can be paved with parallelepipeds a×b×c
. Note, that all small parallelepipeds have to be rotated in the same direction.
For example, parallelepiped 1×5×6
can be divided into parallelepipeds 1×3×5, but can not be divided into parallelepipeds 1×2×3
.
Input
The first line contains a single integer t
(1≤t≤105
) — the number of test cases.
Each of the next t
lines contains three integers A, B and C (1≤A,B,C≤105
) — the sizes of the parallelepiped.
Output
For each test case, print the number of different groups of three points that satisfy all given conditions.
Example
Input
4
1 1 1
1 6 1
2 2 2
100 100 100
Output
1
4
4
165
Note
In the first test case, rectangular parallelepiped (1,1,1)
can be only divided into rectangular parallelepiped with sizes (1,1,1)
.
In the second test case, rectangular parallelepiped (1,6,1)
can be divided into rectangular parallelepipeds with sizes (1,1,1), (1,1,2), (1,1,3) and (1,1,6)
.
In the third test case, rectangular parallelepiped (2,2,2)
can be divided into rectangular parallelepipeds with sizes (1,1,1), (1,1,2), (1,2,2) and (2,2,2).
题意:
有一个 的长方体,将其分成 的小正方体,其中 问这样的abc小正方体能有多少种?
分析:
首先我们能够想到的就是abc至少一个是A的因子,一个是B的因子,一个是C的因子。
如果直接用组合数学进行推公式的话,需要考虑的情况太多,细节太多,一般人绝对考虑不全。
我们整体考虑对于a,b,c每个数无非有7中情况,所以我们考虑用三位二进制来表示状态
001 是A的因数
010 是B的因数
011 是A的因数也是B的因数即是gcd(A,B)的因数
100 是C的因数
101 是A的因数也是C的因数即是gcd(A,C)的因数
110 是B的因数也是C的因数即是gcd(B,C)的因数
111 是A的因数也是B的因数也是C的因数即是gcd(A,B,C)的因数
根据题意我们完全可以预处理处最大范围内每个数的因子个数,然后每个样例对于所给的A,B,C
求出gcd(A,B),gcd(A,C),gcd(B,C);
我们便可以利用容斥定理求出7种状态的因子个数cnt[i](i = 1,2,…7)
这样对于a,b,c我们只需要枚举每个数的状态(三重循环),并判断保证三个数至少有一个是A的因子B的因子C的因子,这样我们就得到了满足条件的a,b,c的个数。
1.如果说a,b,c都是不同的状态,那么我们就得到三种数量,从每种数量中选择1个,利用组合数很好求
2.但是如果有两个数或者三个数相同的状态,这就要求我们从一定数量中选择有重复个元素举个例子
如果ab状态相同,都是cnt[s],那么我们应该从cnt[s]中选两个,并且可以重复即a选了k,b也选了k
这就需用到有重复的组合公式:
如果从n个元素中选择r个有重复元素,其公式为:
这样对于枚举的一种abc状态,各个数的种类数相乘即可,最后每种abc状态个数相加即为最终答案
是个组合数学好题
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll C(int n,int m){//求组合数
ll ans = 1;
for(int i = 1; i <= m; i++){
ans = ans * (n-i+1) / i;
}
return ans;
}
bool check(int a,int b,int c){//保证可以构成大正方形
if((a & 1) && (b & 2) && (c & 4))
return true;
if((a & 1) && (c & 2) && (b & 4))
return true;
if((b & 1) && (a & 2) && (c & 4))
return true;
if((b & 1) && (c & 2) && (a & 4))
return true;
if((c & 1) && (a & 2) && (b & 4))
return true;
if((c & 1) && (b & 2) && (a & 4))
return true;
return false;
}
int gcd(int a,int b){
if(b == 0)
return a;
return gcd(b,a%b);
}
int cnt[10],use[10];
int fac[maxn];
int main(){
//预处理因子个数
for(int i = 1; i < maxn; i++){
for(int j = i; j < maxn; j += i){
fac[j]++;
}
}
int t,x,y,z;
ll ans;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&x,&y,&z);
int xy = gcd(x,y);
int yz = gcd(y,z);
int xz = gcd(x,z);
int xyz = gcd(xy,z);
//容斥计算出每种状态的因子个数
cnt[7] = fac[xyz];//111
cnt[6] = fac[yz] - fac[xyz];//110
cnt[5] = fac[xz] - fac[xyz];//101
cnt[4] = fac[z] - fac[xz] - fac[yz] + fac[xyz];//100
cnt[3] = fac[xy] - fac[xyz];//011
cnt[2] = fac[y] - fac[xy] - fac[yz] + fac[xyz];//010
cnt[1] = fac[x] - fac[xy] - fac[xz] + fac[xyz];//001
ans = 0;
for(int a = 1; a < 8; a++){
for(int b = a; b < 8; b++){
for(int c = b; c < 8; c++){
if(check(a,b,c)){
memset(use,0,sizeof(use));
use[a]++;
use[b]++;
use[c]++;//标记某种状态出现次数
ll tmp = 1;
for(int i = 1; i < 8; i++){//有使用重复组合数公式
if(use[i])
tmp *= C(cnt[i]+use[i]-1,use[i]);
}
if(tmp > 0)
ans += tmp;
}
}
}
}
printf("%lld\n",ans);
}
return 0;
}