【组合计数】CF1007B Pave the Parallelepiped

题意:

话说出题人在搞笑么。。。全程4个公告。。。

T次询问,每次询问给出一个A、B、C,表示一个 A × B × C 的长方体
求有多少种方案的 a × b × c 能够凑出这个大的长方体 ( 1 a b c )
要求小的立方体必须以同样的方向来凑。


分析:

额,据说还有 O ( n n ) 的方法。。不过我考场上没这么想,我还是写我的 O ( n ) 的算法吧

首先,很显然,如果能够凑出来,那么必然满足 a | A b | B c | C (”|”表示整除)

所以,问题转化为求三元组 ( a , b , c ) 中满足 a | A , b | B , c | C 的方案数 ( a b c )

我们利用容斥的思想,先求出一个包含解的一个较大的集合,再减去其中重复的部分。

我们可以先忽略 ( a b c ) 的条件(即不考虑顺序,令1,2,3与1,3,2是不同方案)

f ( x ) 表示x的因数个数

这样的总方案数即为 f ( A ) × f ( B ) × f ( C )

现在考虑哪些情况重复了。不难想到,如果 a b c 被重复计算的条件是,其中必然有两个元素(不失一般性地设这两个元素是 a b ),满足 a , b | g c d ( A , B )

这样一来,我们可以统计一下所有的情况:

1、 a , b | g c d ( A , B ) , c | C

这种情况下会出现 ( a , b , c ) , ( b , a , c ) 两种情况,排除 a = b 的情况后,要减去一次,所以减去 f ( g c d ( A , B ) ) ( f ( g c d ( A , B ) 1 ) 2 f ( C )
同理还有 b , c | g c d ( B , C ) , a | A a , c | g c d ( A , C ) , b | B 的情况。

但是有个问题,这样一来有些被多减了,即 a , b , c | g c d ( A , B , C )
这又分为两种情况:

a = b c

不妨用一个具体的例子来说明一下:
比如(1,2,2)
当考虑 g c d ( A , B ) 时,我们减去了一次 ( 1 , 2 , 2 )
考虑 g c d ( B , C ) 时,减去了一次 ( 2 , 1 , 2 )
考虑 g c d ( A , C ) 时,减去了一次 ( 2 , 2 , 1 )
总计被减去了3次。然而它在最开始被重复计算的也是3次 ( C 3 1 ) 。所以它被减没了。
所以要加回来,即加上 f ( g c d ( A , B , C ) ) ( f ( g c d ( A , B , C ) ) 1 )

上面除以了2,这里却不除以2,是因为在上面 ( a , b ) ( b , a ) 是一种情况,然而这里的是 ( a , a , b ) ( b , b , a ) ,不是一种情况。

a b c

不妨再用一个例子解释一下:
比如(1,2,3)这组

当考虑 g c d ( A , B ) 时,我们减去了一次 ( 1 , 2 , 3 ) , ( 1 , 3 , 2 ) , ( 2 , 3 , 1 )
考虑 g c d ( B , C ) 时,减去了一次 ( 3 , 1 , 2 ) , ( 2 , 1 , 3 ) , ( 1 , 2 , 3 )
考虑 g c d ( A , C ) 时,减去了一次 ( 2 , 3 , 1 ) , ( 3 , 2 , 1 ) , ( 3 , 1 , 2 )
总计被减去了9次,然而最开始只重复计算了6次 ( 3 ! ) 。本应减去5次,然而多减了4次,所以加回来4次。
即加上 f ( g c d ( A , B , C ) ) ( f ( g c d ( A , B , C ) ) 1 ) ( f ( g c d ( A , B , C ) ) 2 ) 6 4

2、 b , c | g c d ( A , B , C ) a | C a | A a | B

这种情况不妨也用一个例子来说明:
对于 A = 4 , B = 4 , C = 6
当计算 ( 1 , 2 , 4 ) 这一个三元组时
我们首先计算了 ( 1 , 4 , 2 ) , ( 2 , 4 , 1 ) , ( 4 , 1 , 2 ) , ( 4 , 2 , 1 ) 四次

但当我们考虑 g c d ( A , B ) 时,减去了 ( 1 , 4 , 2 ) , ( 2 , 4 , 1 )
考虑 g c d ( B , C ) 时,减去了 ( 4 , 1 , 2 )
考虑 g c d ( A , C ) 时,减去了 ( 1 , 4 , 2 )
所以被剪了4次。要补回来一次。
所以加上 ( f ( g c d ( A , B ) ) f ( g c d ( A , B , C ) ) ) f ( g c d ( A , B , C ) ) ( f ( g c d ( A , B , C ) 1 ) 2
同理还有 b , c | g c d ( A , B , C ) , a | A a | g c d ( A , B , C )
以及 a , c | g c d ( A , B , C ) , b | B b | g c d ( A , B , C )

3、 a | g c d ( A , B ) a | C b | g c d ( B , C ) b | A c | g c d ( A , C ) c | B

举个例子当A=6,B=10,C=15时
考虑 ( 2 , 3 , 5 ) 这组
会被计算到 ( 3 , 2 , 5 ) ( 2 , 5 , 3 ) 这两次,然而我们一次都没减。。。
所以减去一次,即减去
( f ( g c d ( A , B ) ) f ( g c d ( A , B , C ) ) ) ( f ( g c d ( B , C ) ) f ( g c d ( A , B , C ) ) ) ( f ( g c d ( A , C ) ) f ( g c d ( A , B , C ) ) )

至此,所有情况都考虑过了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
int n;
typedef long long ll;
ll f[MAXN],num[MAXN];
int primes[MAXN],isprime[MAXN],tot;
void prepare(){
    f[1]=1;
    for(int i=2;i<=100000;i++){
        if(isprime[i]==0){
            primes[++tot]=i;
            f[i]=2;
            num[i]=1;
        }
        for(int j=1;j<=tot&&i*primes[j]<=100000;j++){
            isprime[i*primes[j]]=1;
            if(i%primes[j]==0){
                num[i*primes[j]]=num[i]+1;
                f[i*primes[j]]=f[i]/(num[i]+1ll)*(num[i*primes[j]]+1ll);
                break;
            }
            f[i*primes[j]]=f[i]*f[primes[j]];
            num[i*primes[j]]=1;
        }
    }
}
int gcd(int x,int y){
    if(y==0)
        return x;
    return gcd(y,x%y);
}
int main(){
    prepare();
    int t,a,b,c;
    SF("%d",&t);
    for(int i=1;i<=t;i++){
        SF("%d%d%d",&a,&b,&c);
        //PF("{%lld %lld %lld}\n",f[a],f[b],f[c]);
        //PF("{%d %d %d}",gcd(a,b),gcd(b,c),gcd(a,c));
        int ab=gcd(a,b),bc=gcd(b,c),ac=gcd(a,c);
        ll ans1=f[a]*f[b]*f[c]; 
        ll ans2=(f[ab]*f[ab]-f[ab])/2ll*f[c];
        ll ans3=f[a]*(f[bc]*f[bc]-f[bc])/2ll;
        ll ans4=f[b]*(f[ac]*f[ac]-f[ac])/2ll;
        int td=gcd(gcd(a,c),b);
        ll ans5=(f[td]*f[td]-f[td])+f[td]*(f[td]-1ll)*(f[td]-2ll)/6ll*4ll;
        ll ans6=(f[ab]-f[td])*f[td]*(f[td]-1ll)/2ll;
        ll ans7=(f[bc]-f[td])*f[td]*(f[td]-1ll)/2ll;
        ll ans8=(f[ac]-f[td])*f[td]*(f[td]-1ll)/2ll;
        ll ans9=(f[ab]-f[td])*(f[bc]-f[td])*(f[ac]-f[td]);
        ll ans=ans1-ans2-ans3-ans4+ans5+ans6+ans7+ans8-ans9;
        /*if(ans==212)
            PF("[%d,%d,%d]\n",a,b,c);*/
        //PF("%lld %lld %lld %lld %lld",ans1,ans2,ans3,ans4,ans5); 
        PF("%I64d\n",ans);
    }
} 

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/81043195