ACM数论之旅16---母函数(又名生成函数)(痛并快乐着(╭ ̄3 ̄)╭)
(前排出售零食瓜子)
前言:
母函数是个很难的东西,难在数学
而ACM中所用的母函数只是母函数的基础
应该说除了不好理解外,其他都是非常简单的
母函数即生成函数,是组合数学中尤其是计数方面的一个重要理论和工具。
但是ACM中的母函数木有像数学那么深究,应用的都是母函数的一些基本
(就好比方程的配方,因式的分解,写起来容易,你用电脑写起来就麻烦了,所以学计算机就不要老跟数学家瞎闹( ̄3 ̄))
什么是母函数
就是把一个已知的序列和x的多项式合并起来,新产生的多项式就叫原来序列的母函数
至于怎么合并,看这个例子
序列{0,1,2,3,4,5...n}的母函数就是
f(x)=0+x+2x^2+3x^3+4x^4+...+nx^n(这个x没有任何意义,应该说,你不需要把它当做一个函数,你只要知道母函数这么写就可以了)
序列{1,1,1,1,1......}的母函数就是
f(x)=1+x+x^2+x^3+x^4....
二项式展开的序列比如这个{1,4,6,4,1,0,0,0,0,0.....}是C(4,0)到C(4,4)的系数,那它的母函数就是
f(x)=1+4x+6x^2+4x^3+1x^4
母函数就长这样,对正常人来讲,这种东西毫无意义( ° △ °|||)
那看点有意义的东西(以下都是经典题型,我从杭电ACM课件抄来的)
有1克、2克、3克、4克的砝码各一枚,能称出哪几种重量?每种重量各有几种可能方案?
假如x的幂次数表示几克的砝码
那么
1克的砝码表示为1+x^1
2克的砝码表示为1+x^2
3克的砝码表示为1+x^3
4克的砝码表示为1+x^4
每个砝码都可以选择取或不取
所以这里的1可以认为1*x^0,表示不取这颗砝码
那么把这些乘起来
(1+x^1)(1+x^2)(1+x^3)(1+x^4)
=1+(x^1)+(x^2)+2(x^3)+2(x^4)+2(x^5)+2(x^6)+2(x^7)+(x^8)+(x^9)+(x^10)
根据指数来看,我们可以称出0~10这么多的重量,其中3~7的系数为2,说明有2种称的方法
那么我们来细看一遍
0:(什么砝码都不放).......................(1种)
1:1.............................................(1种)
2:2.............................................(1种)
3:3或1+2.....................................(2种)
4:4或1+3.....................................(2种)
5:1+4或2+3.................................(2种)
6:2+4或1+2+3..............................(2种)
7:3+4或1+2+4..............................(2种)
8:1+3+4......................................(1种)
9:2+3+4......................................(1种)
10:1+2+3+4.................................(1种)
分毫不差(・ˍ・*)
所以说母函数在ACM就是这么用的,跟函数没关系,跟写法有关系。。。
再来一题
求用1分、2分、3分的邮票贴出不同数值的方案数:(每张邮票的数量是无限的)
那么
1分:(1+x^1+x^2+x^3+x^4+......)
2分:(1+x^2+x^4+x^6+x^8+......)
3分:(1+x^3+x^6+x^9+x^12+......)
然后这3个乘起来(让电脑去乘吧)
对于这种无限的,题目肯定会给你他询问的数值的范围,计算到最大的范围就可以了
附代码:
#include<cstdio>
typedef long long LL;
const int N = + ;//假如题目只问到100为止
const int MAX = ;//题目只有1,2,3这3种邮票
LL c1[N], c2[N];//c2是临时合并的多项式,c1是最终合并的多项式
int n;
void init(){
c1[] = ;//一开始0的情况算一种
for(int i = ; i <= MAX; i ++){//把1分到MAXN的邮票合并,变成一个多项式
for(int j = ; j < N; j += i){//i分的邮票,步长是i
for(int k = ; j + k < N; k ++){//从x^0到x^N遍历一遍
c2[j + k] += c1[k];//因为j的所有项系数为1,所以c1[k]可以看成c1[k]*1;
}
}
for(int j = ; j < N; j ++){//把c2的数据抄到c1,清空c2
c1[j] = c2[j];
c2[j] = ;
}
}
}
int main(){
init();
while(scanf("%d", &n) != EOF){
printf("%I64d\n", c1[n]);
}
}
我们就来把这个模板用于实际吧
hdu 1028
http://acm.hdu.edu.cn/showproblem.php?pid=1028
题目问一个数字n能够拆成多少种数字的和
比如n=4
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
有5种,那么答案就是5
AC代码:
#include<cstdio>
typedef long long LL;
const int N = + ;
const int MAX = + ;
LL c1[N], c2[N];
int n;
void init(){
c1[] = ;
for(int i = ; i <= MAX; i ++){
for(int j = ; j < N; j += i){
for(int k = ; j + k < N; k ++){
c2[j + k] += c1[k];
}
}
for(int j = ; j < N; j ++){
c1[j] = c2[j];
c2[j] = ;
}
}
}
int main(){
init();
while(scanf("%d", &n) != EOF){
printf("%I64d\n", c1[n]);
}
}
再来,hdu 1398
http://acm.hdu.edu.cn/showproblem.php?pid=1398
题目说一个国家的硬币都是方形的,面值也是方形的
有1块钱,4块钱,9块钱,16块钱......一直到289块钱(17^2)
问想组成n块钱有几种方法
AC代码:
#include<cstdio>
typedef long long LL;
const int N = + ;
const int MAX = ;
LL c1[N], c2[N];
int n;
void init(){
c1[] = ;
for(int i = ; i <= MAX; i ++){
for(int j = ; j < N; j += i*i){
for(int k = ; j + k < N; k ++){
c2[j + k] += c1[k];
}
}
for(int j = ; j < N; j ++){
c1[j] = c2[j];
c2[j] = ;
}
}
}
int main(){
init();
while(scanf("%d", &n) != EOF && n){
printf("%I64d\n", c1[n]);
}
}
都是改一些小地方,都是模板题(o゚ω゚o)
最后一道
hdu 1085
http://acm.hdu.edu.cn/showproblem.php?pid=1085
AC代码:
#include<cstdio>
#include<cstring>
typedef long long LL;
const int N = * (++) + ;
int cost[] = {, , };
LL c1[N], c2[N];
int num[];
int MAX;
int main(){
while(~scanf("%d%d%d", &num[], &num[], &num[])){
if(num[] == && num[] == && num[] == ) break;
memset(c1, , sizeof(c1));
memset(c2, , sizeof(c2));
MAX = num[] + num[] * + num[] * ;//计算最大值
c1[] = ;
for(int i = ; i < ; i ++){
for(int j = ; j <= num[i] * cost[i]; j += cost[i]){
for(int k = ; j + k <= MAX; k ++){
c2[j + k] += c1[k];
}
}
for(int j = ; j < N; j ++){
c1[j] = c2[j];
c2[j] = ;
}
}
for(int i = ; i <= MAX + ; i ++){
if(!c1[i]){
printf("%d\n", i);
break;
}
}
}
}
母函数在数学上真的用处很大,但是我没怎么看到在ACM上有什么太大的用处(可能我做的题还不够多 T_T)
比如刚刚上面的3个例题,都有更快的做法
第一题:动态规划,时间复杂度O(n^2)
#include<cstdio>
const int N = + ;
int dp[N];
int n;
void init(){
dp[] = ;
for(int i = ; i < N; i ++){
for(int j = i; j < N; j ++){
dp[j] += dp[j - i];
}
}
}
int main(){
init();
while(scanf("%d", &n) != EOF){
printf("%d\n", dp[n]);
}
}
第二题:动态规划,时间复杂度O(n^2)
#include<cstdio>
const int N = + ;
int dp[N];
int n;
void init(){
dp[] = ;
for(int i = ; i <= ; i ++){
for(int j = i*i; j < N; j ++){
dp[j] += dp[j - i*i];
}
}
}
int main(){
init();
while(scanf("%d", &n) != EOF && n){
printf("%d\n", dp[n]);
}
}
第三题:≖‿≖✧特判就好了,时间复杂度O(1)
#include<cstdio>
int a, b, c;
int ans;
int main(){
while(~scanf("%d%d%d", &a, &b, &c) && (a || b || c)){
if(a >= || a >= && b >= || a >= && b >= ) ans = a + *b + *c + ;
else if(a == ) ans = ;
else ans = a + *b + ;
printf("%d\n", ans);
}
}
哈哈哈有没有被骗的感觉,有些题目,不要陷进算法里,这题O(1)的复杂度就可以了,如果你用三个for循环,那就太慢了,而且数量不同,还没有办法预处理,如果数据量大,肯定超时
所以,母函数我们只要理解原理就好了
那么ACM的母函数讲完了(*°∀°)
之后是数学上的母函数,不想看的人就可以结束本章内容了(*°∀°)
ACM数论之旅16---母函数(又名生成函数)(痛并快乐着(╭ ̄3 ̄)╭)的更多相关文章
- acm数论之旅--中国剩余定理
ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯) 中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...
- acm数论之旅--欧拉函数的证明
随笔 - 20 文章 - 0 评论 - 73 ACM数论之旅7---欧拉函数的证明及代码实现(我会证明都是骗人的╮( ̄▽ ̄)╭) https://blog.csdn.net/chen_ze_hua ...
- acm数论之旅--组合数(转载)
随笔 - 20 文章 - 0 评论 - 73 ACM数论之旅8---组合数(组合大法好(,,• ₃ •,,) ) 补充:全错排公式:https://blog.csdn.net/Carey_Lu/ ...
- acm数论之旅(转载) -- 逆元
ACM数论之旅6---数论倒数,又称逆元(我整个人都倒了( ̄﹏ ̄)) 数论倒数,又称逆元(因为我说习惯逆元了,下面我都说逆元) 数论中的倒数是有特别的意义滴 你以为a的倒数在数论中还是1/a吗 ( ...
- acm数论之旅--数论四大定理
ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我) (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威 ...
- ACM数论之旅11---浅谈指数与对数(长篇)(今天休息,不学太难的数论> 3<)
c/c++语言中,关于指数,对数的函数我也就知道那么多 exp(),pow(),sqrt(),log(),log10(), exp(x)就是计算e的x次方,sqrt(x)就是对x开根号 pow()函数 ...
- ACM数论之旅6---数论倒数,又称逆元(我整个人都倒了( ̄﹏ ̄))
数论倒数,又称逆元(因为我说习惯逆元了,下面我都说逆元) 数论中的倒数是有特别的意义滴 你以为a的倒数在数论中还是1/a吗 (・∀・)哼哼~天真 先来引入求余概念 (a + b) % p = (a% ...
- ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我)
(本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威尔逊定理 2.欧拉定理 3.孙子定理(中国剩余定理) 4.费马小定理 (提 ...
- acm数论之旅(转载)--素数
https://www.cnblogs.com/linyujun/p/5198832.html 前言:好多学ACM的人都在问我数论的知识(其实我本人分不清数学和数论有什么区别,反正以后有关数学的知识我 ...
随机推荐
- [HNOI2015]开店 树链剖分,主席树
[HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...
- [SDOI2018]战略游戏 圆方树,树链剖分
[SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中 ...
- P3877 [TJOI2010]打扫房间
xswl以为是个插头dp,然后发现就是个sb题 相当于就是个匹配.每个格子度数为2,所以可以匹配2个相邻的点.匹配显然的用网络流.最后check有没有不匹配的点即可. #include<bits ...
- 详解 nginx location ~ .*\.(js|css)?$ 什么意思?
语法规则: location [=|~|~*|^~] /uri/ { … } = 开头表示精确匹配 ^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可.nginx不对url做编码,因 ...
- SSIS 发送邮件
在SSIS中Send Mail的方法主要有三种,使用Send Mail Task,使用Script Task和使用存储过程msdb.dbo.sp_send_dbmail. 一,使用Send Mail ...
- 腾讯云服务器linux Ubuntu操作系统搭建ftp服务器vsftpd
腾讯云服务器linux Ubuntu操作系统安装ftp服务器vsftpd 操作系统: Ubuntu Server 16.04.1 LTS 64位 下面我将系统重装, 一步一步从头开始,安装FTP服务器 ...
- vue.js和vue-router和vuex快速上手知识
vue.js和vue-router和vuex快速上手知识 一直以来,认为vue相比react而言,学习成本会更低,会更简单,但最近真正接触后,发现vue的各方面都有做一些客户化的优化,有一些亮点,但也 ...
- jmeter控制器(一)
简单控制器: 也就是最简单的控制器,里面没有任何内容的,如下图所示: 当我设置线程为循环10次时,运行简单控制器及下边的注册,设置如下图: 通过查看结果数得知,注册只成功了一次 ,再注册时出现邮箱已存 ...
- xml解析数据信息并实现DBManager操作mysql
先前一直都是用的直接用加载驱动 然后创建连接进行操作数据 如果我的数据库换了 那么要修改的地方也比较多 不利于维护 所以就想到了将所有配置连接信息都用xml封装起来 以至于我每次都只要修改一下我的 ...
- navicat连接mysql出现1251错误
刚刚安装热乎的navicat发现出现1251错误,原因不大清楚,找到一个解决办法: 将mysql的密码重新重置一遍: 1.打开命令行 ,进入mysql所在的目录,输入 mysql -uroot -p ...