目录
定义
作用
模板
题目
hdu1085
hdu1171
hdu1398
hdu2152
hdu1709
hdu2069
hdu2065
hdu1521
生成函数即母函数,是组合数学中尤其是计数方面一个重要理论和工具。
对于任意数列用一个函数联系起来,我们称G(x)为该数列的生成函数
-----------------------------------------------------------
我们可以用生成函数来求出斐波那契数列的通项公式,解法如下:
---------------------------------------------------------------
从一道简单的题目开始练起
我们有1克,2克,3克,4克的砝码各一个,还有一个天平,假设天平左边不能放砝码的话(左物右码),能称出哪些重量的物品,并求出对应方案数
解:我们用来表示方案,其中表示方案数, 表示重量
则只用1克可以称出 ,1表示不放
只用2克可以称出 ,同理3的 ,4的 ,最后因为相互独立,可以乘起来
则
例如重量为6的有1,2,3和2,4两种方案
--------------------------------------------------------------
这次我们有质量为a1,a2,a3,a4...ak克的砝码各一个,还有一个天平,左右两边都能放但是物品只能放左边,问重量为n克的物品有几种称法
解我们用 来表示第i个砝码,其中 表示质量为ai的砝码放在天平左边,1表示不放,表示放在右边
因为相互独立乘起来就可以的到G(x),最后输出的系数
----------------------------------------------------------
下面给出模板(系数都是1的那种)
#include
#include//memset和memcpy都在这里
int main(){
const int manN=100001;
int n;
//a是x的系数,b是中间变量,v是每个物品的价值,n1和n2是物品的最少数量和最多数量
int a[maxN],b[maxN],v[n],n1[n],n2[n];
memset(a,0,sizeof(n);
a[0]=1;
for(int i=0;i
如果数据量比较大,可以考虑用第二个模板
#include
#include//memset和memcpy都在这里
int main(){
const int manN=100001;
int n;
//a是x的系数,b是中间变量,v是每个物品的价值,n1和n2是物品的最少数量和最多数量
int a[maxN]={1},b[maxN],v[n],n1[n],n2[n],last=0,last2;//last是上一次乘完之后最大的幂,last2是这次最大能到达的幂
for(int i=0;i
---------------------------
来点题目试一下
题目大意是说,给你1,2,5这几个硬币,每一个有a,b,c个,问你最小的不能达到的价值是多少
模板题
#include
#include
int main(){
const int maxN=9000;
//n数组是每个硬币有多少个,v是硬币的价值
int a[maxN],b[maxN],n[3],v[3]={1,2,5},last,last2;
while(scanf("%d%d%d",&n[0],&n[1],&n[2])&&n[0]+n[1]+n[2]>0){
last=0;
a[0]=1;
for(int i=0;i<3;++i){
last2=last+v[i]*n[i];//硬币是没有最大数的限制的,所以不需要min(maxN
memset(b,0,sizeof(int)*(last2+1));
for(int j=0;j<=last;++j)
for(int k=0;k<=n[i]&&j+k*v[i]<=last2;++k)b[j+k*v[i]]+=a[j];
memcpy(a,b,sizeof(int)*(last2+1));
last=last2;
}
int result=0;
for(result=0;result<=last2;++result)//找到第一个达不到价值(有可能从0到last2都能达到,所以不能中间输出后break
if(!a[result])break;
printf("%d\n",result);
}
return 0;
}
-----------------------------------------------------
题目大意有n个物品,每个物品都有价值v和数量m,要分成两堆,使价值尽量接近,
解:也是个模板题,得到所有系数后,从总价值的一半开始往前搜索,得到第一个系数不为0的
#include
#include
int main(){
const int maxN=250010;
int a[maxN],b[maxN],n2[50],v[50],last,last2,n;
while(scanf("%d",&n)&&n>=0){
for(int i=0;i>1;
while(!a[result])--result;
printf("%d %d\n",last-result,result);
}
return 0;
}
-----------------------------------------------------------
题目大意:有几种硬币价值为1的平方到17的平方,每种硬币数量不限,问价值n的组成方法有几种
模板题
#include
#include
int main(){
const int maxN=301;
int a[maxN]={1},b[maxN],n;
for(int i=1;i<=17;++i){
memset(b,0,sizeof(b));
for(int j=0;j
---------------------------------------
中文题,这次每个价值有上下限了
#include
#include
int main(){
const int maxN=101;
int a[maxN],b[maxN],n1[maxN],n2[maxN],last,last2,n,m;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i=m&&a[m])printf("%d\n",a[m]);
else printf("0\n");
}
return 0;
}
-----------------------------
题目大意:给你几个砝码,左右两边都能放,问哪些质量不能被称到
解:
#include
#include
#include
int main(){
const int maxN=10001;
int a[maxN],b[maxN],v[100],result[100],last,last2,n,cnt;
while(scanf("%d",&n)!=EOF){
for(int i=0;i
-----------------------------------------
题目大意:有1,5,10,25,50这几种硬币,要组成价值n有几种方案,用的硬币数量加起来不能超过100个
解:这是一道二维的母函数,数据量不大,控制一下硬币的数量和价值,硬肛就行了
#include
#include
int main(){
int a[251][101]={1},b[251][101]={},v[]={1,5,10,25,50},result[251]={1},n;
for(int i=0;i<5;++i){
for(int j=0;j<=250;++j)
for(int k=0;j+k*v[i]<=250;++k)
for(int p=0;k+p<=100;++p)b[j+k*v[i]][k+p]+=a[j][p];
for(int j=0;j<=250;++j)
for(int k=0;k<=100;++k){
a[j][k]=b[j][k];
b[j][k]=0;
}
}
for(int i=1;i<=250;++i)
for(int j=0;j<=100;++j)result[i]+=a[i][j];
while(scanf("%d",&n)!=EOF)printf("%d\n",result[n]);
return 0;
}
---------------------------------
解:指数型生成函数,比较难一点,取n个为 次方,但是取哪个都无所谓,,最后要用泰勒公式化简
所以x的n次方的系数
#include
const int mod=100;
//快速幂
int quickMod(int a,long long int b){
int result=1;
while(b){
if(b&1)result=result*a%mod;
a=a*a%mod;
b>>=1;
}
return result;
}
int main(){
int t;
long long int n;//指数型生成函数(x+x^2/(2!)+x^4/(4!)+....)^2(1+x+x^2/(2!)+x^3/(3!)+....)^2
//由泰勒公式e^x=1+x+x^2/(2!)+x^3/(3!)+.... e^(-x)=1-x+x^2/(2!)-x^3/(3!)+....
//原式=((e^x+e^(-x))/2)^2 *e^2x=((e^2x+1)/2)^2=(e^4x+2e^2x+1)/4=(1+4x+(4x)^2/2!+....+2(1+2x+(2x)^2/2!)+....+1)/4
//=(sigma(i=0到n-1)(4^i+2*2^i)/i!)x^i/4+1/4=sigma(i=0到n-1)(4^(i-1)+2^(i-1))x^i+1/4
//所以x的n次方的系数 4^(n-1)+2^(n-1)
while(scanf("%d",&t)&&t){
for(int i=1;i<=t;++i){
scanf("%lld",&n);
printf("Case %d: %d\n",i,(quickMod(4,n-1)+quickMod(2,n-1))%mod);
}
printf("\n");
}
return 0;
}
-------------------------------------------------
指数型母函数
#include
#include
int main(){
const int maxN=11;
long long int fact[maxN]={1};
for(int i=1;i
hdu1028,2079,2082,2110都可以去练一下