Coin Count——ACM生成函數的應用

 
NEUOJ 1050 Coin Count----Generate Function
一,原題及數據  
Problem 1050 - Coin Counting
Time Limit:1000MS  Memory Limit:65536KB
Total Submit:76  Accepted:10
Description
You are given n coins, and you can take r coins of them. But before taking them, you have to tell how many different combinations can be.
May be you are given many r, so you must tell the answer for each r.
 
Input
Input consists of less than 100 test cases. Each test case begins with two integers n (0 < n &lt;= 50), m (0 &lt;= m &lt;= n). The next line will
contain the values (numbers in the range 1 to n) of the n coins you are to choose from. Two coins with the same value are considered equivalent.
Then in the last line for that test case, you'd have m values for r. There will be a single space separating two consecutive numbers in a line.
Input is terminated by a test case where n=0, you must not process this test case.
 
Outpu
tFor each test case, print the test case number. And for each query number r, print the number of different combinations that can be formed
if r coins are taken from the given n coins. You can assume that for all input cases, the output will always fit in a 64bit unsigned integer and (0&lt;=r&lt;=n).
 
Sample Input5 2
1 2 3 4 5
1 2
4 1
1 1 3 4
2
0 0
Sample Output
Case 1:
5
10
Case 2:
4
二,思路及示例分析
這個題我作出來仍是頗有感受的,雖然比較簡單。
這個題的突破點就在題目給的提示中,n個任意麪值的硬幣,選擇r塊能夠組成多少種不一樣的面值。這種計數的模型相似C(n,r)的式子,既從n個元素中選擇r個元素,問有多少種選法。
這種類型的就十分適合用生成函數來解決。用生成函數解決問題關鍵是生成函數的設計。這個題目的設計就是要讓x^r的係數表示,從n個硬幣中選取r個硬幣能夠組合的面值數。
例如,x 表示選擇1枚的面值數,x^2,表示選擇2枚後的面值數。
生成函數的通常形式是:
F(x)=(1+a1x+a2x^2+..+anx^n)(1+b1x+...+bnx^n)...(1+...+kn*x^n)
      =1+q1x+q2x^2+...+qnx^n+...   ——(1)
有幾個不一樣的數通常就有幾個不一樣的因子。
按照這個思路,思考題目給的例子。
例1。由於5個數選1個的種數爲5,故該例中F(x)中一次項爲5x。同理,二次項爲10x^2。係數恰好爲C(5,1),C(5,2),對應爲(x+1)^5的次數。
故猜想F(x)=(1+x)(1+x)(1+x)(1+x)(1+x)=(1+x)^5。
惋惜的是這個式子,不適合例2。若是將這個式子應用到例2則有F(x)=(1+x)^3。很顯然x^2的係數爲C(3,2)!=4。爲何?緣由是出現了重複的數1。
在選兩個數的過程當中,1能夠不選,能夠被選1次,能夠被選2次。一個因子裏能夠用x^k表示x有k次被選的機會。
因爲例2中1有2次被選的機會,4,5各有1次被選的機會。這樣例2的生成函數就能夠設計爲F(x)=(1+x+x^2)(1+x)(1+x)。對這個式子展開,顯然x^2的係數爲4。
假設這個題的輸入數據爲a1,a2,a3,...,a^n,其中ai重複出現的次數爲ki(i>=1,k&gt;=1)。
由此該題的生成函數就能夠設計爲:
F(x)=(1+x+...+x^k1)(1+x+...+x^k2)....(1+x+...+x^kn)。
所以這個題能夠化爲統計ai出現的次數,展開F(x),求x^r的係數問題。
三,程序代碼 
#include<stdio.h>
#include<iostream>

using namespace std;
const int lmax=3000;
int e[lmax+1];//i e

unsigned long long A1[lmax+1],A2[lmax+1];//    

int n;
int t,q;

void initn()
{

    n=0;
    for(int i=1;i<=t;i++)
    if(e[i])
    n+=e[i];
}// max e

void generateFunction()
{
int i,j,k;
for(i=0;i<=n;i++)
{
A1[i]=A2[i]=0;
}
for(i=0;i<=e[1];i++)// 1+x+...+x^count[k]
A1[i]=1;
        for(i=2;i<=n;i++)
{
for(j=0;j<=n;j++)
for(k=0;k<=e[i]&&k+j<=n;k++)
{
                                A2[j+k]+=A1[j];
}
for(j=0;j<=n;j++)
{
A1[j]=A2[j];
A2[j]=0;
}
}
}
int main()
{
int a,i,j=0;
while(scanf("%d%d",&t,&q)!=EOF,t+q)
{
     memset(e,0,sizeof(e));
     i=0;
     while(i<t)
     {
         scanf("%d",&a);
         e[a]++;
         i++;
     }
     initn();
     generateFunction();
     if(q)
     printf("Case %d:\n",++j);
     while(q--)
     {
     scanf("%d",&a);
     printf("%llu\n",A1[a]);
     }
}
return 0;
}
四,總結
1,某些計數問題能夠用生成函數來解決。
2,生成函數的問題中關鍵是生成函數的設計,其設計能夠結合具體的示例數據和常見的生成函數來設計。
相關文章
相關標籤/搜索