sincerit 母函数(组合问题)

2024-01-01 05:58
文章标签 问题 函数 组合 sincerit

本文主要是介绍sincerit 母函数(组合问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大佬代码: https://blog.csdn.net/yu121380/article/details/79914529
https://blog.csdn.net/xiaofei_it/article/details/17042651?utm_source=blogxgwz0
有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
分析: 我们假设x表示砝码, x的指数表示砝码的重量,这样:
1个1克的砝码可以用函数1+x表示
1个2克的砝码可以用函数1+x2 表示
1个3克的砝码可以用函数1+x3 表示
1个4克的砝码可以用函数1+x4 表示
因为每种砝码只有一个,所以1是表示对该种砝码不取。
几种砝码组合可以称重的情况, 可以用以上几个函数的乘积表示:
(1+x)(1+x2 )(1+x3 )(1+x4 )
所有组合的情况就是展开后的式子:
1 + x + x2 + 2x3 +2x 4 + 2x 5 + 2x 6 + 2x 7 + x 8 + x 9 + x 10
从上面的函数(母函数)知道可称出从1克到10克的重量,系数便是各种重量的方案数

有2个骰子投掷出6点, 共有多少种情况
分析:
我们可以设想骰子出现的点数1, 2, 3, 4, 5, 6和 t , t2 , t3 ,t 4 ,t 5 ,t 6对应起来,则第一个骰子可能出现的点数就与(t+t2 +t3 +t 4 +t 5 +t 6)中的t的各次幂一一对应。
若两个骰子(t+t2 +t3 +t 4 +t 5 +t 6) * (t+t2 +t3 +t 4 +t 5 +t 6) = t2+2t3+3t4+4t5+…中的t6的系数为5, 显然 组成6点的可能有1+5,2+4,3+3, 4+2,5+1这5种方案数

Ignatius and the Princess III
杭电的整数划分母函数实现
输入的n相当于n种砝码(1~n)且每一种有无数多个

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
int sup[150];
int temp[150];
int main() {int n;while (cin >> n) {// 初始化第一个大括号for (int i = 0 ; i <= n; i++) {sup[i] = 1;temp[i] = 0;}// 还剩下n-1个大括号,,且从第2个开始for (int i = 2; i <= n; i++) {// 遍历当前结果多项式的每一项for (int j = 0; j <= n; j++) {for (int k = 0; k + j <= n; k+=i) {  // 遍历当前大括号的每一项temp[j+k] += sup[j];}}for (int j = 0 ; j <= n; j++) {sup[j] = temp[j];temp[j] = 0;}}printf("%d\n", sup[n]); }return 0;
}
#include <iostream>    
using namespace std;        
const int mx = 1000;     
// sup是保存多项式的数组,sup[n]中的值代表xn的系数  
// temp是临时多项式,保存相乘的临时中间情况    
int sup[mx], temp[mx];     
/* 
程序始终只计算两个多项式之间的乘积,多个多项式的情况 
先计算前两个的乘积,将结果作为第一个多项式,再与第三个相乘 
依次类推,sup始终存放当前运算后的结果然后作为被乘多项式, 
*/    
int main()    
{     int target;   //  目标重量, 比如上面的例子里就是10,要<max的值  int i, j, k;    while(cin >> target)    {    for(i=0; i<=target; ++i)       {    sup[i] = 1;     
//初始化第一个多项式,也就是用1g砝码的多项式,  
//注意如果题目没给1g的砝码那么就不能++i,而要加上砝码的质量  temp[i] = 0;    
//将临时区清空,无论第一个多项式质量是几都要全部置零  }    for(i=2; i<=target; ++i)     
// 生成后续的第i个多项式,此题中是2g,i从2开始。  
//如果砝码的值不是规律增长,i可能需要取决于输入  {    for(j=0; j<=target; ++j)     
// 遍历当前结果多项式的每一项(当前结果的第j项)与第i个多项式相乘,  for(k=0; k+j<=target; k+=i)   // 每一个系数都为1就加sup[j] 
// 遍历第i个多项式的每一项,此处构造用小砝码组成大砝码的多项式  {    temp[j+k] += sup[j];    
//幂运算,注意理解  }    for(j=0; j<=target; ++j)      
// 将临时的结果覆盖当前结果,同时把临时结果置零,为下次做准备  {    sup[j] = temp[j];    temp[j] = 0;    }    }    cout << sup[target] << endl;  //输出结果  }    return 0;    
}

Big Event in HDU
一般动态规划过不了

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(array, value) memset(array, value, sizeof(value));
#define N 2500005
int dp[N];
// dp[j]背包容量为j时的最大价值
// 转移方程
// 初始化条件 dp[0] = 0
int num[N];
int main() {int n, v, m;while (cin >> n) {if (n <= 0) break;int a, b, k = 0, sum = 0;while (n--) {cin >> a >> b;while (b--) {num[k++] = a;sum += a;}}dp[0] = 0;int V = sum / 2;for (int i = 0; i < k; i++) {for (int j = V; j >= num[i]; j--) {dp[j] = max(dp[j], dp[j-num[i]]+num[i]);}}sum - dp[V] > dp[V] ? printf("%d %d\n", sum-dp[V], dp[V]) : printf("%d %d\n", dp[V], sum-dp[V]);}return 0;
}

母函数: https://blog.csdn.net/jk13171217/article/details/38303111
题意相当于有n种砝码, 每种砝码重量是weight[i], 并且每一种砝码的个数是number[i],求把这n个砝码平均分两堆,第一堆重量大于等于第二堆

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX 250005
#define N 200
int number[N], weight[N], sup[MAX], temp[MAX];
int main() {int n, v, m;while (cin >> n && (n >= 0)) {int k = 0, sum = 0;while (n--) {cin >> weight[k] >> number[k];sum += weight[k] * number[k];k++;}int V = sum / 2;memset(sup, 0, sizeof(sup));memset(temp, 0, sizeof(temp));// 第一个大括号(1 + x^weight + x^2weight + .. +x^number[k]*weight) for (int i = 0; i <= number[0]; i++)sup[weight[0] * i] = 1;// 从第二个大括号起 (1 + x^weight[1] + x^2weight[1] + ...x^number[1]weight[1]); for (int i = 1; i < k; i++) {for (int j = 0; j <= V; j++) {// 无论多少个k x^k*weight[i]的系数都为1,就如(1+x^2+x^4+x^6+x^8) 两克的砝码有四个一样 for (int k = 0; k*weight[i] <= V && k <= number[i]; k++) // k是第i种砝码的个数temp[k*weight[i]+j] += sup[j];}for (int j = 0; j <= V; j++) {sup[j] = temp[j];temp[j] = 0;} }// 并不是所有的重量都可以凑出,所以就是一半以下得到第一个能组合出的重量的系数说明该重量就是答案 int i;for (i = V; i >= 0; i--) if (sup[i]) break;printf("%d %d\n", sum-i, i); }return 0;
}

Square Coins
题意: 相当于有17种砝码,每一种砝码的重量为12, 22, 32, … 172, 每一种砝码有无限多个
问给定一个重量n,问凑成这个重量的方案数是多少?
(1+t+t2 +t3 +…+tn)(1+t+t4 +t 2 * 4 +t 3 * 4 …+tn) (1+t+t9 +t 2 * 9 +t 3 * 9 …+tn)…(1+t+t17 +t 2 * 17 +t 3 * 17 …+tn)
有17个大括号
母函数:

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
int sup[1000], temp[1000];
int coin[20];
int main() {int n;while (cin >> n, n) {for (int i = 1; i <= 17; i++) coin[i] = i*i;memset(sup, 0, sizeof(sup));memset(temp, 0, sizeof(temp));// 第一个大括号 虽然有无限多个但只要初始化到相等的重量就可以 for (int i = 0; i <= n; i++) sup[i] = 1;// 还有16个大括号 for (int i = 2; i <= 17; i++) {// 遍历当前结果的每一项for (int j = 0; j <= n; j++) {// k表示coin[i]的个数 这个循环是遍历第i个大括号里的每一项 for (int k = 0; k*coin[i]+j <= n; k++) {temp[k*coin[i]+j] += sup[j];}}for (int j = 0; j <= n; j++) {sup[j] = temp[j];temp[j] = 0;}}cout << sup[n] << "\n"; }return 0;
}

动态规划解法–完全背包
dp[i][j] 表示前i种硬币能组成纸币数为j的方案总数
对于第k种硬币 当手中有j-k个硬币的方案数为dp[i-1][j-k]种时再加k个硬币就能组成纸币j的方案数
转移方程: dp[i][j] = dp[i][j] + dp[i-1][j-coin[k]];
初始化条件 dp[1~n][0] = dp[0][1~n] = 0;
换成一维数组 dp[0] = 1; 表示刚好能换成硬币 dp[4-4] = 1刚好有一个为硬币为4的换成纸币种类数为1, 相当于递归的出口

#include <stdio.h>
#include <string.h>
int dp[1000];
int coin[20];
int main() {int n;for (int i = 1; i <= 17; i++) coin[i] = i * i;while (scanf("%d", &n), n) {memset(dp, 0, sizeof(dp)); // 除了dp[0]=1外其他要初始化为0 dp[0] = 1; // 表示刚好能换成硬币 for (int i = 1; i <= 17; i++) {for (int j = coin[i]; j <= n; j++) {dp[j] = dp[j] + dp[j-coin[i]];}}printf("%d\n", dp[n]); }return 0;
}

2082 找单词
输入的26个数字是各个砝码的数量,而各个砝码的重量就是对应的1~26
求小于等于50以下的所有重量的组合总数

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll sup[100], temp[100];
ll p[30];
int main() {int n;cin >> n;while (n--) {for (int i = 1; i <= 26; i++) cin >> p[i];  // 代表个数 memset(temp, 0, sizeof(temp));memset(sup, 0, sizeof(sup));sup[0] = 1;for (int i = 1; i <= 26; i++) { // 同时i代表每种砝码重量 for (int j = 0; j <= 50; j++) {for (int k = 0; k <= p[i] && k * i + j <= 50; k++) {  // 发现k<=p[i]不能少 temp[k*i+j] += sup[j];}}for (int j = 0; j <= 50; j++) {sup[j] = temp[j];temp[j] = 0;}}ll sum = 0;for (int j = 50; j >= 1; j--) sum += sup[j];  // 因为0代表重量为0没有选砝码,所以不加上0的supcout << sum << "\n";}return 0;
}

其他方法:用混合背包

2110 Crisis of HDU

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 10000
#define MOD 10000
int sup[N+5], temp[N+5];
int weight[105], number[105];
int main() {int n;while (cin >> n, n) {int sum = 0;for (int i = 1; i <= n; i++) {cin >> weight[i] >> number[i];sum = sum + weight[i] * number[i];  // 这里蠢了一下 }if (sum % 3 != 0) {cout << "sorry\n";continue;}memset(sup, 0, sizeof(sup));memset(temp, 0, sizeof(temp));for (int i = 0; i <= number[1]; i++) sup[i*weight[1]] = 1;int V = sum / 3;for (int i = 2; i <= n; i++) {for (int j = 0; j <= V; j++) {for (int k = 0; k <= number[i] && k*weight[i]+j <= V; k++) {temp[k*weight[i]+j] =  (temp[k*weight[i]+j] + sup[j]) % MOD;}}for (int j = 0; j <= V; j++) {sup[j] = temp[j];temp[j] = 0;}}if (sup[V]) cout << sup[V];else cout << "sorry";cout << "\n";}return 0;
}

2152 Fruit
设x代表水果 , x的指数代表水果的数量
则有n个大括号(1+x^min + x^(min+1) + x^(min+2) + … x^max)(1+ x^min + x^(min+1) …+x^max)…(1 + x^min + x^min+1 + x^(min+2) + …)
求指数为m的方案数

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 205
int sup[N], temp[N];
int minumber[N], mxnumber[N]; 
int main() {int n, m;while (cin >> n >> m) {for (int i = 1; i <= n; i++) cin >> minumber[i] >> mxnumber[i];memset(sup, 0, sizeof(sup));memset(temp, 0, sizeof(temp));// sup[0] = 1 原本有这个的但提交错了, 后来想到有最小值这个就不能为1了,可能最小数量不是不取for (int i = minumber[1]; i <= mxnumber[1]; i++) sup[i] = 1;for (int i = 2; i <= n; i++) {for (int j = 0; j <= m; j++) {for (int k = minumber[i]; k <= mxnumber[i] && k+j <= m; k++) {temp[k+j] += sup[j];}}for (int j = 0; j <= m; j++) {sup[j] = temp[j];temp[j] = 0;}}cout << sup[m] << "\n";}return 0;
}

这篇关于sincerit 母函数(组合问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/558333

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N