母函数入门

文章详细介绍了母函数的概念,包括普通型和指数型,以及它们在解决排列组合问题和数学公式中的应用,提供了ACM问题的代码示例,如HSquareCoins、IHoldingBin-LadenCaptive!和KTheBalance。还涉及了指数型母函数的扩展,如M排列组合和红色病毒问题的解决方案。
摘要由CSDN通过智能技术生成

1 普通型母函数

1.1 模板代码

母函数即通过幂函数的指数部分解决一些排列组合的问题。
关键在于对c1[], c2[]两个数组的理解:
数组下标储存的是指数,其数值储存的是对应的系数;
c2[]储存下次运算的系数;
c1[]储存截止当前的运算结果。
算式形式

个人认为比较需要理解和分析的是三重循环中每重循环的含义。

#include <bits/stdc++.h>
using namespace std;

const int lmax = 10000;
int c1[lmax+1], c2[lmax+1];
int main()
{
	int n;
	while(cin>>n)
	{
		for(int i=0; i<=n; i++)
		{
			c1[i] = 0;
			c2[i] = 0;
		}
		for(int i=0; i<=n; i++)
			c1[i] = 1;
		for(int i=2; i<=n; i++)
		{
			for(int j=0; j<=n; j++)
				for(int k=0; k+j<=n; k+=i)
				{
					c2[j+k] += c1[j];
				}
			for(int j=0; j<=n; j++)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		cout << c1[n] << endl;
	}
	return 0;
 } 

上述代码是以整数拆分为例:
https://acm.hdu.edu.cn/showproblem.php?pid=1028

1.2 Example

1.2.1 H Square Coins

https://acm.hdu.edu.cn/showproblem.php?pid=1398
这题就是套模板
参考代码:

#include <bits/stdc++.h>
using namespace std;

const int lmax = 10000;
int c1[lmax+1], c2[lmax+1];
int main()
{
	int n;
	while(cin>>n)
	{
		if(n==0)
			break; 
		for(int i=0; i<=n; i++)
		{
			c1[i] = 0;
			c2[i] = 0;
		}
		for(int i=0; i<=n; i++)
			c1[i] = 1;
		for(int i=2; i<=17; i++)
		{
			for(int j=0; j<=n; j++)
				for(int k=0; k+j<=n; k+=i*i)
				{
					c2[j+k] += c1[j];
				}
			for(int j=0; j<=n; j++)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		cout << c1[n] << endl;
	}
	return 0;
 } 

1.2.2 I Holding Bin-Laden Captive!

https://acm.hdu.edu.cn/showproblem.php?pid=1085
此题目不一样/麻烦的地方在于“n”的大小并不是确定的,好在此题目中只有3种硬币,“拆括号”时只用做2次循环,因此我选择的方法是每次循环时手动改变n值的大小,代码如下:

a = num1;
b = num2;
for(int i=2; i<=3; i++)
{
	for(int j=0; j<=a; j++)
		for(int k=0; k<=b*num[i-1]; k+=num[i-1])
		{
			c2[j+k] += c1[j];
		}
	for(int j=0; j<=a+b*num[i-1]; j++)
	{
		c1[j] = c2[j];
		c2[j] = 0;
	}
	a = num1 + num2*num[i-1];
	b = num5;
}

参考代码:

#include <bits/stdc++.h>
using namespace std;

const int lmax = 10000;
int c1[lmax+1], c2[lmax+1];
int main()
{
	int num1, num2, num5, a, b;
	int num[3] = {1, 2, 5};
	while(scanf("%d %d %d", &num1, &num2, &num5))
	{
		if(num1==0&&num2==0&&num5==0)
			break; 
		int n = 1*num1 + 2*num2 + 5*num5;
		for(int i=0; i<=n; i++)
		{
			c1[i] = 0;
			c2[i] = 0;
		}
		for(int i=0; i<=num1; i++)
			c1[i] = 1;
		a = num1;
		b = num2;
		for(int i=2; i<=3; i++)
		{
			for(int j=0; j<=a; j++)
				for(int k=0; k<=b*num[i-1]; k+=num[i-1])
				{
					c2[j+k] += c1[j];
				}
			for(int j=0; j<=a+b*num[i-1]; j++)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
			a = num1 + num2*num[i-1];
			b = num5;
		}
		int ans;
		for(ans=0; ans<=n; ans++)
		{
			if(c1[ans]==0)
			{
				printf("%d\n", ans);
				break;
			}
		}
		if(ans==n+1)
			printf("%d\n", ans);
	}
	return 0;
 } 

1.2.3 K The Balance

https://acm.hdu.edu.cn/showproblem.php?pid=1709
本题最大的不同在于指数上要做减法,但是数组下标不能储存负数,因此一概换种思路,先储存所有加法的情况下可以称出来的重量,再以此为基础做减法,标记减法情况下可以称出来的重量,再进一步判断加法和减法生成的两个数组就可以了,代码如下:

for(int i=sum; i>0; i--)
		{
			if(c1[i]!=0)
			{
				for(int j=1; j<i; j++)
				{
					if(c1[j]!=0)
						b[i-j] = 1;
				}
			}
		}

参考代码:

#include <bits/stdc++.h>
using namespace std;

const int lmax = 100010;
int c1[lmax], c2[lmax];
int main()
{
	int n, qua[lmax], temp[lmax];
	while(cin>>n)
	{
		int sum = 0, b[lmax] = {0};
		for(int i=0; i<n; i++)
		{
			scanf("%d", &qua[i]);
			sum += qua[i];
		}
		for(int i=0; i<=sum; i++)
		{
			c1[i] = 0;
			c2[i] = 0;
		}
		for(int i=0; i<=1; i++)
			c1[i*qua[0]] = 1;
		for(int i=2; i<=n; i++)
		{
			for(int j=0; j<=sum; j++)
				for(int k=0; j+k*qua[i-1]<=sum&&k<=1; k++)
				{
					c2[j+k*qua[i-1]] += c1[j];
				}
			for(int j=0; j<=sum; j++)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		for(int i=sum; i>0; i--)
		{
			if(c1[i]!=0)
			{
				for(int j=1; j<i; j++)
				{
					if(c1[j]!=0)
						b[i-j] = 1;
				}
			}
		}
		int ans = 0;
		for(int i=1; i<=sum; i++)
		{
			if(!c1[i] && !b[i])
				temp[ans++] = i;
		}
		cout << ans << endl;
		if (ans)
		{
    		for (int i = 0; i < ans; i++)
        		cout << temp[i] << " ";
    		cout << endl;
		}
	}
	return 0;
 } 

2 指数型母函数

2.1 Example

2.1.1 M 排列组合

https://acm.hdu.edu.cn/showproblem.php?pid=1521
数学公式
数学公式
指数型母函数与普通母函数的区别在于指数型母函数增加了一步初始化阶乘的步骤,其余基本不变
参考代码(模板代码):

#include <bits/stdc++.h>
using namespace std;

const int N = 21;
double c1[N], c2[N];  //注意是double类型
int val[N], F[N];
//初始化阶乘 
void Factorial()
{
	F[0] = 1;
	for(int i=1; i<20; i++)
	{
		F[i] = F[i-1] * i;
	}
}
int main()
{
	int n, m, i, j, k;
	Factorial();
	while(scanf("%d %d", &n, &m)!=EOF)
	{
		for(int i=0; i<n; ++i)
		{
			scanf("%d", &val[i]);
		}
		memset(c1, 0, sizeof(c1));
		memset(c2, 0, sizeof(c2));
		for(int i=0; i<=val[0]; i++)
		{
			c1[i] = 1.0/F[i];
		}
		for(int i=1; i<n; i++)
		{
			for(int j=0; j<=m; j++)
			{
				for(int k=0; k+j<=m && k<=val[i]; k++)
				{
					c2[j+k] += c1[j]/F[k];
				}
			}
			for(int j=0; j<=m; j++)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		printf("%.0f\n", c1[m]*F[m]);
	}
	return 0;
}

2.1.2 "红色病毒"问题

https://acm.hdu.edu.cn/showproblem.php?pid=2065
此题要将指数型母函数展成泰勒展开式,然后经过一系列化简最后可以用快速幂求得的式子,主要运用到了母函数的思想而非代码。
参考代码:

#include <bits/stdc++.h>
using namespace std;

#define MOD 100
int quickMul(int a, unsigned long long n)
{
	int ans = 1;
	a = a % MOD;
	while(n)
	{
		if(n%2)
			ans = (ans * a) % MOD;
		a = (a * a) % MOD;
		n = n/2;
	}
	return ans;
}
int main()
{
	int t;
	unsigned long long n;
	while(scanf("%d", &t)!=EOF && t!=0)
	{
		for(int i=1; i<=t; i++)
		{
			scanf("%lld", &n);
			int res = (quickMul(4, n-1) + quickMul(2, n-1)) % MOD;
			printf("Case %d: %d\n", i, res);
		}
		printf("\n");
	}
	return 0;
}
  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python函数入门是学习和理解Python编程语言中函数的基本概念和用法。函数是一个可重复使用的代码块,用于执行特定的任务。在Python中,我们可以使用关键字`def`来定义函数,然后通过函数名和参数调用函数。 Python中有几种常见的函数类型和用法,包括: 1. `map()`函数:将一个函数作用于一个序列的每个元素上,并返回一个新的可迭代对象。可以通过`map()`函数来对一个列表中的每个元素应用同一个函数。例如,对于函数`f(x)=x^2`和列表`[1, 2, 3, 4, 5, 6, 7, 8, 9]`,可以使用`map()`函数来将函数应用到列表的每个元素上。 2. `reduce()`函数:将一个函数应用于一个序列的元素,按照函数的规则进行累积计算。`reduce()`函数需要一个函数和一个可迭代对象作为参数,然后将序列的前两个元素传递给函数进行计算,然后将结果与下一个元素继续进行计算,直到将所有的元素计算完毕。例如,可以使用`reduce()`函数计算一个序列的元素的乘积或总和。 3. `filter()`函数:根据函数的返回值是True还是False来过滤序列中的元素。`filter()`函数将一个函数应用于序列的每个元素,并返回一个新的序列,其中包含满足过滤条件的元素。例如,可以使用`filter()`函数来过滤出一个列表中大于5的元素。 4. `sorted()`函数:用于对一个序列进行排序。`sorted()`函数可以接收一个可迭代对象和一个key函数作为参数,根据key函数的规则对序列进行排序。例如,可以按照绝对值大小或字符串长度对一个列表进行排序。 5. 高阶函数:函数可以作为参数传递给另一个函数,或者函数可以作为返回值输出。这样的函数称为高阶函数。例如,可以编写一个接收函数作为参数的函数,并在函数内部调用传入的函数。 6. 装饰器函数:装饰器函数用于修改或扩展函数的行为。装饰器函数本质上是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数,该新函数可以对传入的函数进行修改。装饰器函数通常用于添加额外的功能或对函数进行性能分析。 以上是Python函数入门的一些基本概念和用法。通过学习和掌握这些概念和用法,您可以更好地理解和使用Python中的函数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python函数的入门](https://blog.csdn.net/weixin_51308163/article/details/109382853)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值