Pave the Parallelepiped(容斥原理 预处理每个数的因子个数)

原题:CodeForces - 1008D

题意:

A,B,C A , B , C 的大长方体中有多少中小长方体满足小长方体的三条边可以分别被大的三条边整除

解析:

在假设没有重复计算的时候,答案应该是 F(A)F(B)F(C) F ( A ) ∗ F ( B ) ∗ F ( C ) ( F(x) F ( x ) 表示 x x 的因子的个数)

所以我们只要排除掉这些重复计算的方案数就是答案


如果可能重复计算的话,说明至少有两个数有两个以上的相同因子 (因为只有一个是不会多算的,多算的情况差不多是123和213)


两个数重复(a,b|gcd(A,B),c|C)的情况:

  • gcd(A,B) g c d ( A , B ) 的因子中任意选择两个和c的组合便会多计算一次 所以减去 C2F(gcd(A,B)F(C) C F ( g c d ( A , B ) 2 ∗ F ( C )
  • gcd(B,C) g c d ( B , C ) gcd(A,C) g c d ( A , C ) 同理 减去 C2F(gcd(B,C)F(A)+C2F(gcd(A,C)F(B) C F ( g c d ( B , C ) 2 ∗ F ( A ) + C F ( g c d ( A , C ) 2 ∗ F ( B )

三个数重复 (a,b,c|gcd(A,B,C)) ( a , b , c | g c d ( A , B , C ) ) 的情况:

a=bc a = b ≠ c

(1,2,2)(2,1,2)(2,2,1)(1,1,2)(1,2,1)(2,1,1)这些是我们一开始时算入的,但是在上面两个数重复的情况下把全部都剪完了,多减去了两个(1,1,2)(1,2,2),所以我们要加上 2C2F(gcd(A,B,C)) 2 ∗ C F ( g c d ( A , B , C ) ) 2

abc a ≠ b ≠ c

(1,2,3)(1,3,2)(2,1,3)(2,3,1)(3,1,2)(3,2,1),我们在gcd(A,B)时减去的有(1,2,3)(2,3,1)(1,3,2),同理gcd(B,C)gcd(A,C)各减去三个,多减了3次再加上(1,2,3),所以要加上4个即加上 4C3F(gcd(A,B,C)) 4 ∗ C F ( g c d ( A , B , C ) ) 3


只一个数非一个数因子 (a|gcd(A,B,C),b|gcd(A,B,C),c|gcd(A,B)) ( a | g c d ( A , B , C ) , b | g c d ( A , B , C ) , c | g c d ( A , B ) ) 的情况

A=4,B=4,C=6 (1,2,4)

  • 开始时记下(1,4,2)(2,4,1)(4,1,2)(4,2,1)
  • gcd(A,B)时减去(1,4,2)(2,4,1)
  • gcd(B,C)时减去(4,1,2)
  • gcd(A,C)时减去(1,4,2)

减完了,所以还要加上去,从gcd(A,B)和gcd(A,B,C)的不同的因子中选一个加上gcd(A,B,C)中选两个即加上 (F(gcd(A,B))F(gcd(A,B,C)))C2F(gcd(A,B,C)) ( F ( g c d ( A , B ) ) − F ( g c d ( A , B , C ) ) ) ∗ C F ( g c d ( A , B , C ) ) 2

b|gcd(A,C),a|gcd(B,C)同,加上 (F(gcd(A,C))F(gcd(A,B,C)))C2F(gcd(A,B,C)),(F(gcd(B,C))F(gcd(A,B,C)))C2F(gcd(A,B,C)) ( F ( g c d ( A , C ) ) − F ( g c d ( A , B , C ) ) ) ∗ C F ( g c d ( A , B , C ) ) 2 , ( F ( g c d ( B , C ) ) − F ( g c d ( A , B , C ) ) ) ∗ C F ( g c d ( A , B , C ) ) 2


每个数皆非一个数因子(a|gcd(A,B),b|gcd(B,C),c|gcd(C,A))的情况
A=6,B=10,C=15 (2,5,3)

  • 开始时记下(2,5,3)(3,2,5),但在考虑两个数重复的时候都没有减去
  • 所以要额外 减去
    (F(gcd(A,B))F(gcd(A,B,C)))(F(gcd(A,C))F(gcd(A,B,C)))(F(gcd(B,C))F(gcd(A,B,C))) ( F ( g c d ( A , B ) ) − F ( g c d ( A , B , C ) ) ) ∗ ( F ( g c d ( A , C ) ) − F ( g c d ( A , B , C ) ) ) ∗ ( F ( g c d ( B , C ) ) − F ( g c d ( A , B , C ) ) )

总结:

设 : A=a , B=b , C=c , gcd(A,B,C)=abc , gcd(A,B)=ab , gcd(B,C)=bc , gcd(A,C)=ac

ans=F(a)*F(b)*F(c)-C(F(ab),2)*F(c)-C(F(ac),2)*F(b)-C(F(bc),2)*F(a)
ans+=2*C(F(abc),2)+4*C(F(abc),3)
ans+=(F(ab)+F(bc)+F(ac)-3*F(abc))*C(F(abc),2)
ans-=(F(ab)-F(abc)) * (F(ac)-F(abc)) * (F(bc)-F(abc))

预处理每个数的因子的个数

这算是一个比较常用的知识了吧,而巧合的是这个东西的做法和这题的做法很像

n=pq11pq22...pqkk n = p 1 q 1 ∗ p 2 q 2 . . . p k q k
n的因子数为 (q1+1)(q2+1)...(qk+1) ( q 1 + 1 ) ∗ ( q 2 + 1 ) ∗ . . . ∗ ( q k + 1 )

求A的因子的个数相当于求A的两个互质因子的因子个数之积

  • F(18)=F(2)F(9),(1,2)(1,3,9) F ( 18 ) = F ( 2 ) ∗ F ( 9 ) , 相 当 于 ( 1 , 2 ) 里 面 选 一 个 乘 上 ( 1 , 3 , 9 ) 里 面 选 一 个

在非互质的情况下,会出现重复

  • F(3)=2(1,3),(1,1),(1,3),(3,1),(3,3),F(9)=3(1,3,9) F ( 3 ) = 2 ( 1 , 3 ) , 两 个 三 的 组 合 有 ( 1 , 1 ) , ( 1 , 3 ) , ( 3 , 1 ) , ( 3 , 3 ) , 而 F ( 9 ) = 3 ( 1 , 3 , 9 )

现在考虑的就是去重的情况

设:求解数 A A , A的一个质因数 a a , 有A=apb (ba) ( b 与 a 互 质 )

显然, F(A)=(p+1)F(b) F ( A ) = ( p + 1 ) ∗ F ( b )

F(Aa)=(p+2)F(b) F ( A ∗ a ) = ( p + 2 ) ∗ F ( b )

所以,对于任意 Aa A ∗ a , 我们只需要知道 A A 对于a的次方数 p p , 就可以通过A的因子数转换过来

F(Aa)=F(A)p+2p+1 F ( A ∗ a ) = F ( A ) ∗ p + 2 p + 1


实现起来其实也不难,我们把这个过程塞进素数筛里面,为了统一,我们对于任何数的转换只考虑它的第一个质因子 3926 3 → 9 2 → 6 ,在素数筛的时候记录下每个数的第一个质因子的次方数即可

代码:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100000;
ll f[N+9],p[N+9];
///
bool notpri[N+9];
int pri[N+9>>1],now;
void init(){
    now=0;f[1]=1;
    notpri[0]=notpri[1]=1;
    for(int i=2;i<=N;i++){
        if(!notpri[i])pri[++now]=i,f[i]=2,p[i]=1;
        for(int j=1;j<=now&&pri[j]*i<=N;j++){
            notpri[i*pri[j]]=1;
            if(i%pri[j]==0){//有pri[j]作为质因子时
                f[i*pri[j]]=f[i]*(p[i]+2)/(p[i]+1);
                p[i*pri[j]]=p[i]+1ll;
                break;
            }
            f[i*pri[j]]=f[i]*f[pri[j]];//互质则直接乘
            p[i*pri[j]]=1;
        }
    }
}


int main(){
    init();
    int t;scanf("%d",&t);
    while(t--){
        ll a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
        ll ab=__gcd(a,b),bc=__gcd(b,c),ac=__gcd(a,c);
        ll abc=__gcd(ab,c);

        ll ans=f[a]*f[b]*f[c];

        ans-=(f[ab]*(f[ab]-1ll))/2*f[c];
        ans-=(f[ac]*(f[ac]-1ll))/2*f[b];
        ans-=(f[bc]*(f[bc]-1ll))/2*f[a];

        ans+=f[abc]*(f[abc]-1ll)+(f[abc]*(f[abc]-1ll)*(f[abc]-2ll))*2/3;

        ans+=(f[ab]+f[bc]+f[ac]-3ll*f[abc])*(f[abc]*(f[abc]-1ll))/2;

        ans-=(f[ab]-f[abc])*(f[ac]-f[abc])*(f[bc]-f[abc]);

        printf("%lld\n",ans);
    }
}




添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值