HDU_4390 Number Sequence (容斥原理)

  题目:a1*a2*...*an=b1*b2*…*bn,(ai > 1) 给出b序列,求a序列有多少种。

先不考虑ai > 1这个条件。可以通过费解b_i的质因子得到如下公式:

∏b_i = ∏(p_i^k_i);

pi是∏bi 的某个质因子。

因为a_i 共有n个,所以把每个p_i填到这n个空位置里边去。对于p_i,有C(k_i + n - 1, n - 1);

证明见:http://hi.baidu.com/pp_5/blog/item/73798043ec77781f72f05d51.html/cmtid/6aff22f08c5c85a1a50f523d 

显然,所有的p[]的值为 ∏C(k_i + n - 1, n - 1); (上午问ftiasch❤trl大牛时就是这个地方没想明白。。。让他体会了一把对牛弹琴的感觉。。。深表歉意。)

 

然后考虑ai > 1这个条件。

 已知容次原理:

  

设Ai表示i位置为1这种状态。 则 answer = 

根据容斥原理枚举Ai, Aj, Ak...位置为1的状态。。。。

 

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   x < y ? x : y
#define Max(x, y)   x < y ? y : x
#define E(x)    (1 << (x))

const double eps = 1e-4;
typedef long long LL;
const int inf = ~0u>>2;
using namespace std;

const int N = 110;
const int M = 1000010;
const int MOD = 1e9 + 7;

int c[N][N];
int k[M], t[M];
int num, n;

int prime[N*20];
bool vis[N*20];
int cnt;

void get_prime() {
    CL(vis, true);
    int i, j;
    for(i = 2; i < N*20; ++i) {
        for(j = i*i; j < N*20; j += i) {
            vis[j] = false;
        }
    }
    cnt = 0;
    for(i = 2; i < N*20; ++i) {
        if(vis[i])  prime[cnt++] = i;
    }
}

void init() {
    get_prime();
    CL(c, 0);
    int i , j;
    for(i = 0; i < N; ++i)  c[i][0] = c[i][i] = 1;
    for(i = 2; i < N; ++i) {
        for(j = 1; j < i; ++j) {
            c[i][j] = (c[i-1][j] + c[i-1][j-1])%MOD;
        }
    }
}

LL solve(int x) {
    int m = n, flag = 1, i;

    for(i = 0; i < n; ++i) {
        if(((1<<i)&x) == 0) {
            flag *= -1; m--;
        }
    }
    LL tmp = 1;
    for(i = 0; i < num; ++i) {
        tmp = tmp*LL(c[k[i]+m-1][m-1])%MOD;
    }
    //printf("%d\n", tmp*flag);
    return tmp*flag;
}

int main() {
    //freopen("data.in", "r", stdin);

    init();
    int x, i, j;
    LL ans;

    while(~scanf("%d", &n)) {
        CL(t, 0);
        for(i = 0; i < n; ++i) {
            scanf("%d", &x);
            for(j = 0; prime[j]*prime[j] <= x; ++j) {
                if(x%prime[j] == 0) {
                    while(x%prime[j] == 0) {
                        t[prime[j]]++; x /= prime[j];
                    }
                }
            }
            if(x != 1)   t[x]++;
        }
        num = 0;
        for(i = 2; i < M; ++i) {
            if(t[i] != 0) {
                k[num++] = t[i];
            }
        }
        ans = 0;
       //从N状态开始枚举。。。二进制位为1表示那一位的a_i不等于1,为0则表示等于1。因为proh(a_i) = proh(b_i)所以,a_i不可能全为0。。。
        for(i = (1<<n)-1; i >= 1; --i) {
            ans = (ans + solve(i))%MOD;
        }
        cout << (ans%MOD + MOD)%MOD << endl;
    }
    return 0;
}

 

 

 

 

 

 

posted @ 2012-08-24 16:29  AC_Von  阅读(355)  评论(0编辑  收藏  举报