指数型母函数求排列程序实现

      指数型母函数用来求排列数。它的乘积式以及通项式都会带一个阶乘的倒数。假设{ai}是表示某种排列数的序列,那么母函数应该写作:   

        G(x) = a0 + a1·x + a2·x^2 / 2! + a3·x^3 / 3! + … + an·x^n / n! + …

母函数的乘式也是类似的,一般形如:

        1 + x + x^2 / 2! + x^3 / 3! + … + x^n / n! + …   

        参考http://acm.hdu.edu.cn/showproblem.php?pid=1521,一共有n种物件,每一种物件有ki个,那么从中选m个物件的排列数是多少?    典型的求排列的指数型母函数,代表每种物件的乘积式如下:                                  

           1 + x + x^2 / 2! + … + x^ki / ki!      其中ki表示第i种物件的数量。    

           将这n个乘积式连乘得到G(x),那么 x^m / m! 的系数就是答案。Note,m次项的系数本身不是答案,还要乘以m!才是答案。

#include <cstdio>
#include <algorithm>
using namespace std;
 
double FAC[11] = {
  1.0,1.0,2.0,6.0,24.0,120.0,720.0,
  5040.0,40320.0,362880.0,3628800.0
};
 
int main(){
  int n,m;
  while( EOF != scanf("%d%d",&n,&m) ){
    int a[11];
    for(int i=0;i<n;++i)scanf("%d",a+i);
    
    //初始化
    double c1[11]={0.0},c2[11]={0.0};
    for(int i=0;i<=a[0];++i) c1[i] = 1.0 / FAC[i];
    
    //乘
    for(int i=1;i<n;++i){
      //j+k次的系数依次加上j次的系数,因为k这边的系数始终为1
      //超过m次的不必关心
      for(int j=0;j<=m;++j)
        for(int k=0;k<=a[i]&&k+j<=m;++k)
          c2[j+k] += c1[j] / FAC[k];
            
        //保存结果,清除临时变量
        copy(c2,c2+m+1,c1);
        fill(c2,c2+m+1,0.0);
    }
 
    //确定结果
    double ans = c1[m] * FAC[m];
    printf("%.0lf\n",ans);
  }
  return 0;
}


    
    这个程序的结构与普通型母函数基本无区别。但是由于要除以阶乘,所以用double,而不用int。由于阶乘以及分母的存在,使得指数型母函数的题目有时候可能会涉及到大数问题或者有理数(分子/分母)的问题。
    不过,有时候数学可能会改变一切,关于指数型母函数,也许你根本用不到编程序进行多项式的乘法。还记得下面这个等式吗?
                     e^x = 1 + x + x^2 / 2! + x^3 / 3! + … + x^n / n! + …
    看这个 http://acm.hdu.edu.cn/showproblem.php?pid=2065,A、C只能出现偶数次或者不出现,所以代表A、C的乘积式为
                                               1 + x^2 / 2! + x^4 / 4! + …
    B、D无限制,所以乘积式就如上。4个乘积式连乘出的多项式就是母函数。但由于n可以取到非常巨大的值,所以直接求取一定会超时、超内存。但是,B、D的乘积式就是e^x。而A、C的乘积式就是( e^x + e^(-x) ) / 2,所以母函数是
                  G(x) = e^x · e^x · ( e^x + e^(-x) ) / 2·( e^x + e^(-x) ) / 2
                          = ( ( e ^ 2x + 1 ) / 2 ) ^ 2 
                          = ( e ^ 4x + 2 e ^ 2x + 1 ) / 4
    展开以后,很容易得到关于x^n / n!的系数是4^(n-1) + 2^(n-1)。由于n很大,所以题目要求给出对特定数取模的答案,于是这道题需要编写的代码变成了快速幂取模,而不是多项式乘法或者大数什么的。
 
//利用指数型母函数推导出最后的结果是
//4^(n-1)+2^(n-1)
//由于n是一个极大的数,所以编写一个快速幂函数
#include <cstdio>
typedef unsigned long long ull;

//求x^n % mod
ull powmod(ull x,ull n,ull mod){
  ull ret = 1ULL;
  while(n){
    if ( n & 1 ) ret = ret * x % mod;
    
    x = x * x % mod;
    n >>= 1;
  }
  return ret;
}
 
int main(){
  int t;
  while( scanf("%d",&t) && t ){
    for(int kase=1;kase<=t;++kase){
      ull n;
      scanf("%I64u",&n);
      ull ans = powmod(4ULL,n-1,100ULL) + powmod(2ULL,n-1,100ULL);
      printf("Case %d: %I64u\n",kase,ans%100ULL);
    }
    printf("\n");
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值