hdu 4390 Number Sequence

转自:http://blog.csdn.net/haha593572013/article/details/7901900

感谢上面博客的博主提供思路和代码


http://acm.hdu.edu.cn/showproblem.php?pid=4390


题目可以抽象成:给你一个 x1*a1  + x2*a2 +x3*a3 ……+xn*an  把 这 x1 + x2 + x3 + ……+xn 个元素分成n个集合,每个集合的元素都不为空的种类数

其中每个元素并不是都不相同,如果每个元素都不一样直接全排列就行了,但是有一样的也有不一样的,具体做法就是把一样的集合单独考虑,比如 x1  个 a1元素,看它能够分配到n个集合的种类数,因为元素是一样的所以是组合而不需要考虑排列,然后根据乘法法则相乘即可……

  组合数学知识: m个相同的数放进n个容器中,就相当于有n-1块隔板,总的方案就是C(n-1,n+m-1)

然后就相当于依次将每种素数放入n个容器中,记录下每种素数各有多少放法,假设有tot种素数 f(i) 表示第i种素数的放法,那么如果n个数中某些数可以为1,即n个容器某些位置可以不放数,总的方案就是f(1)*f(2)*...*f(tot),然后再减去所有出现某些容器不放数的情况,可以用容斥原理做,即当前求的总方案数减去有一个容器放0的方案数,加上有两个位置放0的方案数,减去至少有三个位置放0的方案数。。。。。


再次感谢博主: http://blog.csdn.net/haha593572013/article/details/7901900


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>

using namespace std;
const int maxn=1010;
const int mod=1000000007;
vector<int> p;
typedef long long ll;
ll c[maxn][maxn];
int n;

void init()
{
    c[0][0]=1;
    for(int i=1;i<maxn;i++)
    {
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
}
void find(int n)
{
     for(int i=2;i*i<=n;i++)
       if(n%i==0)
       {
           while(n%i==0) p.push_back(i),n/=i;
       }
     if(n!=1) p.push_back(n);
}
ll fun(int n,int part)
{
    return c[n+part-1][part-1];
}
ll solve()
{
     sort(p.begin(),p.end());
     int sz=p.size();
     /*for(int i=0;i<sz;i++)
        cout<<p[i]<<" ";
     cout<<endl;*/
     int a[110],tot=0;
     for(int i=0,j;i<sz;i=j)
     {
         j=i+1;
         while(j<sz&&p[j]==p[i]) j++;
         a[++tot]=j-i;
     }
     ll ans=0;
     for(int i=0;i<=n;i++)
     {
         ll tmp=c[n][i];
         for(int j=1;j<=tot;j++) tmp=tmp*fun(a[j],n-i)%mod;
         if(i&1) ans=((ans-tmp)%mod+mod)%mod;
         else ans=(ans+tmp)%mod;
     }
     return (ans%mod+mod)%mod;
}
int main()
{
    //freopen("1001.in","r",stdin);
   // freopen("my.out","w",stdout);
    init();
    int a;
    while(scanf("%d",&n)==1)
    {
        for(int i=0;i<n;i++) scanf("%d",&a),find(a);
        printf("%I64d\n",solve());
        p.clear();
    }
    return 0;
}

还有个组合数学题目:  http://blog.csdn.net/struggle_mind/article/details/7903958

你可能感兴趣的:(hdu 4390 Number Sequence)