1. 程式人生 > >組合數學-普通型生成函式(母函式)-hdu2082 找單詞

組合數學-普通型生成函式(母函式)-hdu2082 找單詞

 Problem Description

假設有x1個字母A, x2個字母B,..... x26個字母Z,同時假設字母A的價值為1,字母B的價值為2,..... 字母Z的價值為26。那麼,對於給定的字母,可以找到多少價值<=50的單詞呢?單詞的價值就是組成一個單詞的所有字母的價值之和,比如,單詞ACM的價值是1+3+14=18,單詞HDU的價值是8+4+21=33。(組成的單詞與排列順序無關,比如ACM與CMA認為是同一個單詞)。  Input 輸入首先是一個整數N,代表測試例項的個數。
然後包括N行資料,每行包括26個<=20的整數x1,x2,.....x26.  Output 對於每個測試例項,請輸出能找到的總價值<=50的單詞數,每個例項的輸出佔一行。  Sample Input 2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9  Sample Output 7 379297

知識點:

母函式(生成函式):   

    生成函式有普通型生成函式和指數型生成函式兩種(本題是普通型)。

    形式上,普通型母函式用於解決多重集的組合問題,

                指數型母函式用於解決多重集的排列問題。

    母函式還可以解決遞迴數列的通項問題(例如使用母函式解決斐波那契數列,Catalan數的通項公式)。

普通母函式:

    構造母函式G(x), G(x) = a0 + a1*x + a2*clip_image002 + a3*clip_image002[4] +....+ an*clip_image002[6],  則稱G(x)是數列a0,a1…an的母函式。

    通常普通母函式用來解多重集的組合問題,其思想就是構造一個函式來解決問題,一般過程如下:

    1.建立模型:物品n種,每種數量分別為k1,k2,..kn個,每種物品又有一個屬性值p1,p2,…pn,(如本題的字母價值),

      求屬性值

為m的物品組合方法數。(若數量ki無窮 也成立,即對應下面式子中第ki項的指數一直到無窮)

    2.構造母函式:G(x)=(1+clip_image002[18]+clip_image002[20]clip_image002[22])(1+clip_image002[26]+clip_image002[28]+…clip_image002[30])…(1+clip_image002[32]+clip_image002[34]+…clip_image002[38])        (一)

                                =a0 + a1*x + a2*clip_image002 + a3*clip_image002[4] +....+ akk*clip_image002[16]     (設kk=k1·p1+k2·p2+…kn·pn)  (二)

                  G(x)含義: ak 為屬性值為k的組合方法數。

母函式利用的思想:

    1.把組合問題的加法法則和冪級數的乘冪對應起來。

    2.把離散數列和冪級數對應起來,把離散數列間的相互結合關係對應成為冪級數間的運算關係,最後由冪級數形式來

       確定離散數列的構造。

程式碼實現:

    求G(x)時一項一項累乘。先令G=1=(1+0*x+0*clip_image002[56]+…0*clip_image002[58]),再令G=G*(1+clip_image002[18]+clip_image002[20]clip_image002[22])得到形式(二)的式子…最後令G=G*(1+clip_image002[32]+clip_image002[34]+…clip_image002[38])。

題解:

1.建模:物品(字母)26種,每種數量x1,x2…x26,屬性值為1,2,3..26,求屬性值和<=50的組合方法數。

2.G(x)=(1+clip_image002[40]+clip_image002[42]clip_image002[44])(1+clip_image002[46]+clip_image002[48]+…clip_image002[50])…(1+clip_image002[52]+…clip_image002[54])

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long a[60],b[60];
 
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        a[0]=1;
        int x;
        for(int i=1;i<=26;i++)
        {
            scanf("%d",&x);
            for(int j=0;j<=50;j++)
            {
                for(int k=0;k<=x&&(j+k*i<=50);k++)
                {
                    b[j+k*i]+=a[j];
                }
            }
            for(int j=0;j<=50;j++)
            {
                a[j]=b[j];
                b[j]=0;
            }
        }
        long long ans=0;
        for(int i=1;i<=50;i++)
            ans+=a[i];
        cout<<ans<<endl;
    }
}
AC Code