首页 > 代码库 > hdu 4390 Number Sequence (容斥原理)

hdu 4390 Number Sequence (容斥原理)

Number Sequence

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 790    Accepted Submission(s): 331


Problem Description
Given a number sequence b1,b2…bn.
Please count how many number sequences a1,a2,...,an satisfy the condition that a1*a2*...*an=b1*b2*…*bn (ai>1).
 

Input
The input consists of multiple test cases. 
For each test case, the first line contains an integer n(1<=n<=20). The second line contains n integers which indicate b1, b2,...,bn(1<bi<=1000000, b1*b2*…*bn<=1025).
 

Output
For each test case, please print the answer module 1e9 + 7.
 

Sample Input
2 3 4
 

Sample Output
4
Hint
For the sample input, P=3*4=12. Here are the number sequences that satisfy the condition: 2 6 3 4 4 3 6 2
 

Source
2012 Multi-University Training Contest 10
 
题意:
 求一个数列 a1,a2,..an,使a 1*a 2*...*a n=b 1*b 2*…*b n ,其中ai>1;

思路:
刚开始没什么思路,在网上找了很久,发现很多博客都是千篇一律的,后来总结了一下。。

1.先对每个bi跟姐质因数,用map保存每个因子出现的次数,此时ai*a2*...an的质因子为map保存的;
2.现在的问题就是将n个相同的数放进m个盒子里,假设盒子可为空,则所有情况为C(n+m-1,n-1),然后,对map里保存的因子个数逐个代入计算,
再应用乘法原理就可以求出盒子可为空时所有的情况。
3.题目要求盒子不可为空,这就要用到数学归纳法了:
f[i]-放入i个数能够为空的种数,g[i]-放入i个数不能为空的种数:

f[1]=g[1]
f[2]=g[2]+C(2,1)*g[1],
f[3]=g[3]+C(3,1)*g[2]+C(3,2)*g[1],
......
g[n]=f[n]-C(n,1)*f[n-1]+C(n,2)*f[n-2]-...

依次计算有i个盒子为空的组合数,应用容斥原理:-g[1]+g[2]-g[3]+g[4]....;


My Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<map>

#define N 100010
#define mod 1000000007
#define lson l,mid,idx<<1
#define rson mid+1,r,idx<<1|1
#define lc idx<<1
#define rc idx<<1|1
const double EPS = 1e-11;
const double PI = acos(-1.0);
const double E=2.718281828;
typedef long long ll;

const int INF=1000010;

using namespace std;

int C[1001][45];///组合数
map<int,int>mp;

void init()
{
    for(int i=0; i<=1000; i++)
        C[i][0]=1;///i个选0个为1;
    for(int i=1; i<=1000; i++)
        for(int j=1; j<=42; j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;///c(n,k)=c(n-1,k)+c(n-1,k-1),可以自己证明
}

void Fenjie(int n)///分解质因数
{
    for(int i=2; i*i<=n; i++)
    {
        if(n%i==0)
        {
            while(n%i==0)
            {
                mp[i]++;
                n/=i;
            }
        }
        if(n==1)
            break;
    }
    if(n>1)
        mp[n]++;
}

int main()
{
    init();
    int n;
    while(cin>>n)
    {
        mp.clear();
        int b;
        for(int i=0; i<n; i++)
        {
            scanf("%d",&b);
            Fenjie(b);
        }
        ll ans=0;
        for(int i=0; i<n; i++)///容斥原理
        {
            ll tem=C[n][i];
            map<int,int>::iterator it;
            for(it=mp.begin(); it!=mp.end(); it++)///计算有i个盒子为空的组合数
            {
                int t=it->second+n-i-1;
                tem*=C[t][n-i-1];
                tem%=mod;
            }
            if(i%2)
                ans-=tem,ans+=mod;
            else
                ans+=tem;
            ans%=mod;
        }
        cout<<ans%mod<<endl;
    }
    return 0;
}


hdu 4390 Number Sequence (容斥原理)