poj3904 Sky Code —— 唯一分解定理 + 容斥原理 + 组合

题目链接:http://poj.org/problem?id=3904

类似题目poj2773(题解):http://blog.csdn.net/DOLFAMINGO/article/details/72669432


题解:

给出n个数, 随便挑4个, 使得这四个数的最大公约数为1, 问有多少种组合?

思路:先用容斥原理计算出四个数的最大公约数>=1的组合数, 然后再用总数C(n,4)减之。


1.将每个数进行分解质因数, 然后再根据这些质因数组合出不同的因子,并记录这个因子出现的次数以及由多少个质因数构成。

2.容斥原理:比如因子2的个数为a,则四个数公约数为2的个数 为C(a,4),因子3的个数为b,则四个数公约数为3的个数为C(b,4),因子6(2*3)的个 数为c,则四个数公约数的个数为C(c,4)。 但是公约数为2的情况中或者公约数为3的情况中可能包括公约数为6的情况,相当于几个集合求并集,这就需要容斥定理来做。

3.如果这个因子出现的次数>=4, 则表明这个因子可以作为某四个数的最大公约数的因子。

4.根据容斥原理:当这个因子的由奇数个质因数构成时, 加; 当这个因子由偶数个质因子构成时, 减。

5. ans = C(n,4) - gcd(a,b,c,d)!=1的组合数。



代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define pb push_back
#define mp make_pair
#define ms(a, b)  memset((a), (b), sizeof(a))
#define eps 0.0000001
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+7;
const int maxn = 1e4+10;

LL pri[maxn], fac_num[maxn], fac_pri[maxn];
LL n, cnt;

LL C(LL x)
{
    return x*(x-1)*(x-2)*(x-3)/24;
}

void Divide(LL x)
{
    cnt = 0;
    for(int i = 2; i*i<=x; i++)
    {
        if(x%i==0)
        {
            pri[cnt++] = i;
            while(x%i==0)  x /= i;
        }
    }
    if(x!=1) pri[cnt++] = x;
}

void Unit()
{
    for(LL s = 1; s < (1<=4)   //这个因子的个数必须不小于4, 才能成为4个数的约束
        {
            if(fac_pri[i]&1)    //素数个数为奇数时, 加
                tmp += C(fac_num[i]);
            else                //素数个数为偶数时, 减
                tmp -= C(fac_num[i]);
        }
    }
    LL ans = C(n) - tmp;    //总的减去gcd(a,b,c,d)!=1的个数,即为gcd(a,b,c,d)=1的个数。
    printf("%lld\n", ans);
}

int main()
{
    while(scanf("%lld",&n)!=EOF)
    {
        init();
        solve();
    }
}


你可能感兴趣的:(组合数学,数论)