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 <= 50), m (0 <= m <= 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<=r<=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>=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,生成函数的问题中关键是生成函数的设计,其设计能够结合具体的示例数据和常见的生成函数来设计。