hdu 4390 Number Sequence

来源:互联网 发布:暴风tv电视怎么样知乎 编辑:程序博客网 时间:2024/06/05 16:55

转自: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