Codeforces 1008D/1007B

题意略。

思路:

由于这个长方体是可以翻转的,所以我们不必考虑小长方体3个维度的出处,反正3条边一定有长有短能分出大小。

现在我们来考虑A,B,C三个数字,如果它们3个产生的因子互不相同,分别产生了a,b,c个因子,那么本题的答案就是a * b * c。

可是在现实中,这三个数字是会产生重合的因子的,也就是说a,b可能有公共部分,如果此时我们还将a和b相乘,那么我们会给答案带来增解。

现在我们将因子分成a,b,c,ab,bc,ac,abc这7种互不重叠,而并集却又是所有因子的个数的情况。

我们为小长方体选择的3维的因子出处分别为 [a,ab,ac,abc],[b,ab,bc,abc],[c,ac,bc,abc]。

当我们的因子没有选到同一区域内时,我们直接相乘即可,否则我们就要选择特殊的计算方法来解决。

这个题目在这里有一定容斥的思想。即便我们分类区域,但是由于有一些区域是共用的,所以还是会产生重复,这里用hash来去重。

同时要注意这题的实现技巧。

详见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;
const int a = 1;
const int b = 2;
const int c = 3;
const int ab = 4;
const int bc = 5;
const int ac = 6;
const int abc = 7; 

LL cnt[maxn],numb[10];
int store[10];
vector<int> va,vb,vc;
set<LL> st;

void init(){
    for(int i = 1;i < maxn;++i)
        for(int j = i;j < maxn;j += i)
            cnt[j] += 1;
    
    va.push_back(a);
    va.push_back(ab);
    va.push_back(ac);
    va.push_back(abc);
    
    vb.push_back(b);
    vb.push_back(bc);
    vb.push_back(ab);
    vb.push_back(abc);
    
    vc.push_back(c);
    vc.push_back(ac);
    vc.push_back(bc);
    vc.push_back(abc);
}
LL cal2(LL x){
    return x + x * (x - 1) / 2;
}
LL cal3(LL x){
    return x + x * (x - 1) + x * (x - 1) * (x - 2) / 6;
}
LL gcd(LL a,LL b){
    return b == 0 ? a : gcd(b,a % b);
}

int main(){
    init();
    LL T,A,B,C;
    scanf("%lld",&T);
    while(T--){
        st.clear();
        scanf("%lld%lld%lld",&A,&B,&C);
        LL dab = gcd(A,B),dbc = gcd(B,C),dac = gcd(A,C),dabc = gcd(dab,C);
        numb[abc] = cnt[dabc];
        numb[ab] = cnt[dab] - numb[abc],numb[bc] = cnt[dbc] - numb[abc],numb[ac] = cnt[dac] - numb[abc];
        numb[a] = cnt[A] - numb[ab] - numb[ac] - numb[abc];
        numb[b] = cnt[B] - numb[ab] - numb[bc] - numb[abc];
        numb[c] = cnt[C] - numb[ac] - numb[bc] - numb[abc];

        LL ans = 0;
        for(int i = 0;i < va.size();++i){
            for(int j = 0;j < vb.size();++j){
                for(int k = 0;k < vc.size();++k){
                    store[0] = va[i],store[1] = vb[j],
                    store[2] = vc[k];
                    sort(store,store + 3);
                    LL hash = 0;
                    for(int u = 0;u < 3;++u)
                        hash = hash * 10 + store[u];
                    if(st.count(hash)) continue;
                    st.insert(hash);
                    int one = store[0],two = store[1],
                    three = store[2];
                    if(one == two && two == three){
                        ans += cal3(numb[one]);
                    }
                    else if(one == two){
                        ans += numb[three] * cal2(numb[one]);
                    }
                    else if(two == three){
                        ans += numb[one] * cal2(numb[two]);
                    }
                    else if(one == three){
                        ans += numb[two] * cal2(numb[one]);
                    }
                    else{
                        ans += numb[one] * numb[two] * numb[three];
                    }
                }
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/tiberius/p/9362197.html