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;
}
#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,生成函数的问题中关键是生成函数的设计,其设计可以结合具体的示例数据和常见的生成函数来设计。
转载于:https://blog.51cto.com/snowteng17/305602