codeforces 1008D Pave the Parallelepiped(数学,处理因子)

题目链接

a,b,c分别是A,B,C的因数,但a,b,c可能会有重复的排列出现,所以需要删掉

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=1e5;
int t,a,b,c,nu[maxn+10],num[maxn+10];
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
#define A 0
#define B 1
#define C 2
#define AB 3
#define BC 4
#define AC 5
#define ABC 6
vector<int>va,vb,vc;
void init()//预处理每个数因子的数量
{
    for(int i=1;i<=maxn;i++)
    {
        for(int j=i;j<=maxn;j+=i)
            nu[j]++;
    }
    va.push_back(A);va.push_back(AB);
    va.push_back(AC);va.push_back(ABC);

    vb.push_back(B);vb.push_back(AB);
    vb.push_back(BC);vb.push_back(ABC);

    vc.push_back(C);vc.push_back(AC);
    vc.push_back(BC);vc.push_back(ABC);
}

int cal3(int x){
    int res = 0;
    res += x + x*(x-1) + x*(x-1)*(x-2)/6;//三部分取相同,两部分取相同,三部分都不同
    return res;
}

int cal2(int x){
    int res = 0;
    res += x + x*(x-1)/2;//两部分相同,两部分不同
    return res;
}
map<ll,int>ma;
int kt[5],p[10];
int main()
{
    init();
    scanf("%d",&t);
    while(t--)
    {
        ma.clear();
        scanf("%d%d%d",&a,&b,&c);

        int ab=gcd(a,b),bc=gcd(b,c),ac=gcd(a,c);
        int abc=gcd(ab,c);

        int nABC=nu[abc];
        int nAB=nu[ab]-nABC;
        int nBC=nu[bc]-nABC;
        int nAC=nu[ac]-nABC;
        int nA=nu[a]-nAB-nAC-nABC;
        int nB=nu[b]-nAB-nBC-nABC;
        int nC=nu[c]-nAC-nBC-nABC;

        num[ABC]=nABC;
        num[AB]=nAB;
        num[AC]=nAC;
        num[BC]=nBC;
        num[A]=nA;
        num[B]=nB;
        num[C]=nC;

        int ans=0;
        ma.clear();
        for(int i=0;i<va.size();i++)
        for(int j=0;j<vb.size();j++)
        for(int k=0;k<vc.size();k++)
        {
            kt[0]=va[i],kt[1]=vb[j],kt[2]=vc[k];
            sort(kt,kt+3);
            int x=kt[0],y=kt[1],z=kt[2];
            ll tmp=0;
            for(int l=0;l<3;l++)
                tmp=1ll*tmp*maxn+1ll*kt[l];
            if(ma[tmp]) continue;///打标记去重
            ma[tmp]=1;
            if(x==y&&y==z)
                ans+=cal3(num[x]);
            else if(x==y)
                ans+=num[z]*cal2(num[x]);
            else if(y==z)
                ans+=num[x]*cal2(num[y]);
            else ans+=num[x]*num[y]*num[z];
        }
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值