NOIP 2011 提高组 计算系数(vijos 1739)(方法:二项式定理)

     <————————————————————————————————————————————————————————>

            附:   题目链接                vijos 1739                                              地址:https://www.vijos.org/p/1739

     <————————————————————————————————————————————————————————>

            PS:本题关键是二次项定理:(a+b)^n = \sum_{k=0}^n {n \choose k}  a^{n-k}b^k,其中,{n \choose k}=\frac{n!}{k!(n-k)!} 又有\rm
{C}^k_n(即组合数)等记法。

            由二次项定理推结果:

             c = ax; d = by;    原式 变为 ( c + d ) k

             则   cn     *  dm      的系数 为  C(k,m)

             —> anxn  *  bmym 的系数 为  C(k , m)

            —> xn ym             的系数 为  an  *  bm  *  C(k , m)

 

            求 C(k , m) 成为了结题关键,按照常规算法, C(k , m) = m! / ( k! * (m-k)! )

             但    很显然 直接累乘 会爆范围              ( 过程中不能mod,因为还要约分母)

             所以 这题最好用 组合 的递推算法:   C(n , m) = C(n-1 , m) + C(n-1 , m-1)

             该题解采用 滚动数组 以节省空间。         (值得一提的是 k<=1000 , m<=k)

     <————————————————————————————————————————————————————————>

             const mo=10007;                        //要求的取mod

             var
             c:array[0..1,0..1000] of longint;    //滚动数组 求 组合
             a,b,k,n,m,i,j,new,old:longint;         //new为 当前决策点,old 为上一决策点

             begin
               readln(a,b,k,n,m);
               a := a mod mo;
               b := b mod mo;                        //值得一提的是,a、b没mod后几个数据会爆longint,如vijos上不加只能有80 - =
               c[0,0] := 1;
               c[1,0] := 1;

     <————————————————————————————————————————————————————————>

                                             读入数据,并对a,b进行处理,当然也可不处理,采用int64

     <————————————————————————————————————————————————————————>

             for i := 1 to k do begin
               new:=1-new;
               old:=1-new;
               for j := 1 to m do if i >= j then                     //记得加 i>=j  0 0,否则组合会求错 -  =
               c[new,j] := (c[old,j-1] + c[old,j]) mod mo;
             end;

     <————————————————————————————————————————————————————————>

                                                滚动数组求组合,过程中不边算边mod也会爆范围 - =

     <————————————————————————————————————————————————————————>

              j := c[new,m];
              for i := 1 to n do j := (j * a) mod mo;
              for i := 1 to m do j := (j * b) mod mo;
              writeln(j);

     <————————————————————————————————————————————————————————>

                                            乘a^n,b^m,得最后结果,同样边乘边mod,理由同上

     <————————————————————————————————————————————————————————>

end.

     <————————————————————————————————————————————————————————>

                                                                                                                                                      End。

posted @ 2013-10-15 22:39  哥少先队的  阅读(337)  评论(0编辑  收藏  举报