部分摘自這位大佬的博客https://www.cnblogs.com/linyujun/p/5207730.html
生成函數即母函數,是組合數學中尤其是計數方面的一個重要理論和工具。 最早提出母函數的人是法國數學家LaplaceP.S.在其1812年出版的《概率的分析理論》中明確提出“生成函數的計算”。 生成函數的應用簡單來說在於研究未知(通項)數列規律,用這種方法在給出遞推式的情況下求出數列的通項。
在這里我們不去高深地研究數學上母函數,而是講講簡單的母函數應用。
1.母函數引入
就是把一個已知的序列和x的多項式合並起來,新產生的多項式就叫原來序列的母函數
序列{0,1,2,3,4,5...n}的母函數就是
f(x)=0+x+2x^2+3x^3+4x^4+...+nx^n(這個x沒有任何意義,應該說,你不需要把它當做一個函數,你只要知道母函數這么寫就可以了)
序列{1,1,1,1,1......}的母函數就是
f(x)=1+x+x^2+x^3+x^4....
二項式展開的序列比如這個{1,4,6,4,1,0,0,0,0,0.....}是C(4,0)到C(4,4)的系數,那它的母函數就是
f(x)=1+4x+6x^2+4x^3+1x^4
這些東西對於我們來說並沒有說明意義,母函數對我們來說只是一個工具,是一個載體,那來看看母函數是怎么樣裝載數據的吧!
例1:若有1克、2克、3克、4克的砝碼各一 枚,能稱出哪幾種重量?各有幾種可能方案?
假如x的指數表示砝碼
那么
1克的砝碼表示為1+x^1
2克的砝碼表示為1+x^2
3克的砝碼表示為1+x^3
4克的砝碼表示為1+x^4
每個砝碼都可以選擇取或不取
所以這里的1可以認為1*x^0,表示不取這顆砝碼
那么把這些乘起來
(1+x^1)(1+x^2)(1+x^3)(1+x^4)
=1+(x^1)+(x^2)+2(x^3)+2(x^4)+2(x^5)+2(x^6)+2(x^7)+(x^8)+(x^9)+(x^10)
根據指數來看,我們可以稱出0~10這么多的重量,其中3~7的系數為2,說明有2種稱的方法
那么我們來細看一遍
0:(什么砝碼都不放).......................(1種)
1:1.............................................(1種)
2:2.............................................(1種)
3:3或1+2.....................................(2種)
4:4或1+3.....................................(2種)
5:1+4或2+3.................................(2種)
6:2+4或1+2+3..............................(2種)
7:3+4或1+2+4..............................(2種)
8:1+3+4......................................(1種)
9:2+3+4......................................(1種)
10:1+2+3+4.................................(1種)
分毫不差
所以說母函數在ACM就是這么用的,跟函數沒關系,跟寫法有關系。
例2:求用1分、2分、3分的郵票貼出不同數值的方案數,每種郵票可以有無限張。
因郵票允許重復,故母函數為:
對於這種連續相乘,我們人類是很討厭的,但對於計算機這種重復運算是很輕松的,我們只要將我們解多項式的思路帶進去即可。
2.代碼說明
我們首先知道對於最后得到的那一個母函數,系數代表的是方案數,而指數代表的是組成的數值,運算過程就是多項式的乘法。而兩個多次方程的乘法,運算無非是系數相乘,指數相加,僅僅是這個方程的兩個信息的運算。那能不能用什么數據結構直接表示出一個對象的這個兩個信息呢?首先想到的可能是結構體,結構體可以用來表示一個對象的多個信息,但是運算繁瑣;其實用數組就可以了,下標代表組成的數值,數組取值代表方案數!!!
a.求用1分、2分、3分的郵票貼出不同數值的方案數:(每張郵票的數量是無限的)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define MAX 310 6 int a[MAX];///最終合並的多項式 7 int b[MAX];///臨時合並用的多項式 8 int n; 9 const int N=110; 10 using namespace std; 11 void init() 12 { 13 int i,j,k; 14 a[0]=1;///一開始的0的情況 15 for (i=1; i<=3; i++)///代表1分,2分,3分三個多項式的合並 16 { 17 for (j=0; j<N; j+=i)///i分的郵票,步長為i 18 { 19 for (k=0; k+j<N; k++)///從x^0到x^N遍歷一遍 20 { 21 b[j+k]+=a[j];///核心 22 } 23 } 24 for (j=0; j<N; j++)///b中數據抄到a,b清空 25 { 26 a[j]=b[j]; 27 b[j]=0; 28 } 29 } 30 } 31 int main() 32 { 33 int i,j,k; 34 init(); 35 while(scanf("%d",&n)!=EOF) 36 { 37 printf("%d\n",a[n]); 38 } 39 return 0; 40 }
b.hdu 1028
http://acm.hdu.edu.cn/showproblem.php?pid=1028
題目問一個數字n能夠拆成多少種數字的和
比如n=4
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
有5種,那么答案就是5
其實這個題就可以轉換成使用1~N個數,每個數可以多次使用,能組成的數有多少種方案?

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define MAX 130 6 #define N 130 7 #define ll long long int 8 ll a[MAX]; 9 ll b[MAX]; 10 int n; 11 using namespace std; 12 void init() 13 { 14 int i,j,k; 15 a[0]=1; 16 for (i=1; i<=MAX; i++) 17 { 18 for (j=0; j<N; j+=i) 19 { 20 for (k=0; k+j<N; k++) 21 { 22 b[j+k]+=a[k]; 23 } 24 } 25 for (j=0; j<N; j++) 26 { 27 a[j]=b[j]; 28 b[j]=0; 29 } 30 } 31 } 32 int main() 33 { 34 init(); 35 while(scanf("%d",&n)!=EOF) 36 { 37 printf("%lld\n",a[n]); 38 } 39 return 0; 40 }
c.hdu 1398
http://acm.hdu.edu.cn/showproblem.php?pid=1398
題目說一個國家的硬幣都是方形的,面值也是方形的
有1塊錢,4塊錢,9塊錢,16塊錢......一直到289塊錢(17^2)
問想組成n塊錢有幾種方法

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define ll long long int 6 #define MAX 17 7 #define N 305 8 using namespace std; 9 ll a[N]; 10 ll b[N]; 11 void init() 12 { 13 int i,j,k; 14 a[0]=1; 15 for (i=1; i<=MAX; i++) 16 { 17 for (j=0; j<N; j+=i*i) 18 { 19 for (k=0; k+j<N; k++) 20 { 21 b[j+k]+=a[k]; 22 } 23 } 24 for (j=0; j<N; j++) 25 { 26 a[j]=b[j]; 27 b[j]=0; 28 } 29 } 30 } 31 int main() 32 { 33 int n; 34 init(); 35 while(scanf("%d",&n)!=EOF) 36 { 37 if(n==0) 38 { 39 break; 40 } 41 printf("%lld\n",a[n]); 42 } 43 return 0; 44 }