数学专题训练2 组合计数

1. 硬币购物

4 种面值的硬币,第 i 种的面值是 C i C_i Ci​。 n n n​ 次询问,每次询问给出每种硬币的数量 D i D_i Di​ 和一个价格 S S S​,问付款方式。 n ≤ 1 0 3 , S ≤ 1 0 5 n\leq 10^3,S\leq 10^5 n103,S105​.

如果用背包做的话复杂度是 O ( 4 n S ) O(4nS) O(4nS),无法承受。这道题最明显的特点就是硬币一共只有四种。抽象模型,其实就是让我们求方程 ∑ i = 1 4 C i x i = S , x i ≤ D i \sum_{i=1}^4C_ix_i=S,x_i\leq D_i i=14Cixi=S,xiDi 的非负整数解的个数。

采用同样的容斥方式, x i x_i xi 的属性为 x i ≤ D i x_i\leq D_i xiDi. 套用容斥原理的公式,最后我们要求解

∑ i = 1 4 C i x i = S − ∑ i = 1 k C a i ( D a i + 1 ) \sum_{i=1}^4C_ix_i=S-\sum_{i=1}^kC_{a_i}(D_{a_i}+1) i=14Cixi=Si=1kCai(Dai+1)

也就是无限背包问题。这个问题可以预处理,算上询问,总复杂度 O ( 4 S + 2 4 n ) O(4S+2^4n) O(4S+24n)

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll f[N];
int T, c[5], d[5], s;
int main()
{for(int i = 0; i < 4; i++) scanf("%d", &c[i]);scanf("%d", &T);f[0] = 1;for(int i = 0; i < 4; i++){for(int j = c[i]; j <= 100000; j++){f[j] += f[j - c[i]];}}while(T--){for(int i = 0; i < 4; i++) scanf("%d", &d[i]);scanf("%d", &s);ll res = 0;for(int i = 0; i < (1 << 4); i++){int sum = 0, sign = 1;for(int j = 0; j < 4; j++){if(i >> j & 1) sign *= -1, sum += c[j] * (d[j] + 1);}if(s - sum >= 0) res += sign * f[s - sum];}printf("%lld\n", res);}
}

2. 错位排列计数

对于 1 ∼ n 1\sim n 1n 的排列 P P P 如果满足 P i ≠ i P_i\neq i Pi=i,则称 P P P n n n 的错位排列。求 n n n 的错位排列数。

很简单,离散1也讲过,答案就是 n ! ∑ k = 0 n ( − 1 ) k k ! n!\sum\limits_{k=0}^{n}\frac{(-1)^k}{k!} n!k=0nk!(1)k

3. 完全图子图染色问题

A 和 B 喜欢对图(不一定连通)进行染色,而他们的规则是,相邻的结点必须染同一种颜色。今天 A 和 B 玩游戏,对于 n n n​ 阶 完全图 G = ( V , E ) G=(V,E) G=(V,E)​。他们定义一个估价函数 F ( S ) F(S) F(S)​,其中 S 是边集, S ⊆ E S\subseteq E SE​. F ( S ) F(S) F(S)​ 的值是对图 G ′ = ( V , S ) G'=(V,S) G=(V,S)​ 用 m m m​ 种颜色染色的总方案数。他们的另一个规则是,如果 ∣ S ∣ |S| S​ 是奇数,那么 A 的得分增加 F ( S ) F(S) F(S)​,否则 B 的得分增加 F ( S ) F(S) F(S)​. 问 A 和 B 的得分差值。

即求: ∑ S ⊆ E ( − 1 ) ∣ S ∣ − 1 F ( S ) \sum\limits_{S\subseteq E}(-1)^{|S|-1}F(S) SE(1)S1F(S)​,并且要求边集不能是空集.​

相邻结点染同一种颜色,我们把它当作属性。在这里我们先不遵守染色的规则,假定我们用 m 种颜色直接对图染色。对于图 G ′ = ( V , S ) G'=(V,S) G=(V,S),我们把它当作 元素属性 x i = x j x_i=x_j xi=xj 的含义是结点 i,j 染同色(注意,并未要求 i,j 之间有连边)。

而属性 x i = x j x_i=x_j xi=xj 对应的 集合 定义为 Q i , j Q_{i,j} Qi,j,其含义是所有满足该属性的图 G ′ G' G 的染色方案,集合的大小就是满足该属性的染色方案数,集合内的元素相当于所有满足该属性的图 G ′ G' G 的染色图。

回到题目,“相邻的结点必须染同一种颜色”,可以理解为若干个 Q Q Q 集合的交集。因此可以写出

F ( S ) = ∣ ⋂ ( i , j ) ∈ S Q i , j ∣ F(S)=\left|\bigcap_{(i,j)\in S}Q_{i,j}\right| F(S)= (i,j)SQi,j

上述式子右边的含义就是说对于 S 内的每一条边 ( i , j ) (i,j) (i,j) 都满足 x i = x j x_i=x_j xi=xj 的染色方案数,也就是 F ( S ) F(S) F(S).

是不是很有容斥的味道了?由于容斥原理本身没有二元组的形式,因此我们把 所有 的边 ( i , j ) (i,j) (i,j) 映射到 T = n ( n + 1 ) 2 T=\frac{n(n+1)}{2} T=2n(n+1) 个整数上,假设将 ( i , j ) (i,j) (i,j) 映射为 k , 1 ≤ k ≤ T k,1\leq k\leq T k,1kT,同时 Q i , j Q_{i,j} Qi,j 映射为 Q k Q_k Qk. 那么属性 x i = x j x_i=x_j xi=xj 则定义为 P k P_k Pk.

同时 S 可以表示为若干个 k 组成的集合,即 S ⇔ K = { k 1 , k 2 , ⋯ , k m } S\Leftrightarrow K=\{k_1,k_2,\cdots,k_m\} SK={k1,k2,,km}.(也就是说我们在边集与数集间建立了等价关系)。

而 E 对应集合 M = { 1 , 2 , ⋯ , n ( n + 1 ) 2 } M=\left\{1,2,\cdots,\frac{n(n+1)}{2}\right\} M={1,2,,2n(n+1)}. 于是乎

F ( S ) ⇔ F ( { k i } ) = ∣ ⋂ k i Q k i ∣ F(S)\Leftrightarrow F(\{ {k_i}\})=\left|\bigcap_{k_i}Q_{k_i}\right| F(S)F({ki})= kiQki

那么要求的式子展开

A n s = ∑ K ⊆ M ( − 1 ) ∣ K ∣ − 1 ∣ ⋂ k i ∈ K Q k i ∣ = ∑ i ∣ Q i ∣ − ∑ i < j ∣ Q i ∩ Q j ∣ + ∑ i < j < k ∣ Q i ∩ Q j ∩ Q k ∣ − ⋯ + ( − 1 ) T − 1 ∣ ⋂ i = 1 T Q i ∣ \begin{split} Ans &= \sum_{K\subseteq M}(-1)^{|K|-1}\left|\bigcap_{k_i\in K}Q_{k_i}\right|\\ &= \sum_{i}|Q_i|-\sum_{i<j}|Q_i\cap Q_j|+\sum_{i<j<k}|Q_i\cap Q_j\cap Q_k|-\cdots+(-1)^{T-1}\left|\bigcap_{i=1}^TQ_i\right| \end{split} Ans=KM(1)K1 kiKQki =iQii<jQiQj+i<j<kQiQjQk+(1)T1 i=1TQi

于是就出现了容斥原理的展开形式,因此对这个式子逆向推导

A n s = ∣ ⋃ i = 1 T Q i ∣ Ans=\left|\bigcup_{i=1}^TQ_i\right| Ans= i=1TQi

再考虑等式右边的含义,只要满足 1 ∼ T 1\sim T 1T 任一条件即可,也就是存在两个点同色(不一定相邻)的染色方案数!而我们知道染色方案的全集是 U U U,显然 ∣ U ∣ = m n |U|=m^n U=mn. 而转化为补集,就是求两两异色的染色方案数,即 A m n = m ! n ! A_m^n=\frac{m!}{n!} Amn=n!m!. 因此

A n s = m n − A m n Ans=m^n-A_m^n Ans=mnAmn

解决这道题,我们首先抽象出题目数学形式,然后从题目中信息量最大的条件, F ( S ) F(S) F(S) 函数的定义入手,将其转化为集合的交并补。然后将式子转化为容斥原理的形式,并 逆向推导 出最终的结果。这道题体现的正是容斥原理的逆用。

4. 容斥原理求最大公约数为 k k k 的数对个数

1 ≤ x , y ≤ N 1 \le x, y \le N 1x,yN f ( k ) f(k) f(k) 表示最大公约数为 k k k 的有序数对 ( x , y ) (x, y) (x,y) 的个数,求 f ( 1 ) f(1) f(1) f ( N ) f(N) f(N) 的值。

欧拉函数(找 g c d ( x k , y k ) = 1 gcd(\frac{x}{k},\frac{y}{k}) = 1 gcd(kx,ky)=1 的数量)和莫比乌斯反演都可以写,但是不如容斥原理来得简单。

由容斥原理可以得知,先找到所有以 k k k公约数 的数对,再从中剔除所有以 k k k 的倍数为 公约数 的数对,余下的数对就是以 k k k最大公约数 的数对。即 f ( k ) = f(k)= f(k)= k k k公约数 的数对个数 − - k k k 的倍数为 公约数 的数对个数。

进一步可发现,以 k k k 的倍数为 公约数 的数对个数等于所有以 k k k 的倍数为 最大公约数 的数对个数之和。于是,可以写出如下表达式:

f ( k ) = ⌊ ( N / k ) ⌋ 2 − ∑ i = 2 i ∗ k ≤ N f ( i ∗ k ) f(k)= \lfloor (N/k) \rfloor ^2 - \sum_{i=2}^{i*k \le N} f(i*k) f(k)=⌊(N/k)2i=2ikNf(ik)

由于当 k > N / 2 k>N/2 k>N/2 时,我们可以直接算出 f ( k ) = ⌊ ( N / k ) ⌋ 2 f(k)= \lfloor (N/k) \rfloor ^2 f(k)=⌊(N/k)2,因此我们可以倒过来,从 f ( N ) f(N) f(N) 算到 f ( 1 ) f(1) f(1) 就可以了。于是,我们使用容斥原理完成了本题。

for (long long k = N; k >= 1; k--) {f[k] = (N / k) * (N / k);for (long long i = k + k; i <= N; i += k) f[k] -= f[i];
}

上述方法的时间复杂度为 O ( ∑ i = 1 N N / i ) = O ( N ∑ i = 1 N 1 / i ) = O ( N log ⁡ N ) O( \sum_{i=1}^{N} N/i)=O(N \sum_{i=1}^{N} 1/i)=O(N \log N) O(i=1NN/i)=O(Ni=1N1/i)=O(NlogN)

附赠三倍经验供大家练手。

GCD SUM

给定 n ( n ≤ 1 0 5 ) n(n \le 10^5) n(n105),求 ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) \sum\limits_{i = 1}^{n}\sum\limits_{j = 1}^{n}gcd(i,j) i=1nj=1ngcd(i,j).

我们可以用容斥原理求出 f ( i ) = ∑ i = 1 n ∑ j = 1 n [ g c d ( i , j ) = k ] f(i) = \sum\limits_{i = 1}^{n}\sum\limits_{j = 1}^{n}[gcd(i,j)= k] f(i)=i=1nj=1n[gcd(i,j)=k]​​ 的值,然后答案就是 ∑ i = 1 n i ∗ f ( i ) \sum\limits_{i=1}^n i * f(i) i=1nif(i)​.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll f[N];
int main()
{int n;scanf("%d", &n);ll ans = 0;for(int i = n; i >= 1; i--){f[i] = 1LL * (n / i) * (n / i);for(int j = 2 * i; j <= n; j += i) f[i] -= f[j];ans += 1LL * i * f[i];}printf("%lld\n", ans);return 0;
}

仪仗队

在这里插入图片描述

即计算 ∑ i = 1 n − 1 ∑ j = 1 n − 1 [ g c d ( i , j ) = 1 ] \sum\limits_{i=1}^{n - 1}\sum\limits_{j=1}^{n-1}[gcd(i,j)=1] i=1n1j=1n1[gcd(i,j)=1]​​,最后答案要加2. 注意特判 n = 1 n = 1 n=1​ 的情况.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll f[N];
int main()
{int n;scanf("%d", &n);n--;for(int i = n; i >= 1; i--){f[i] = 1LL * (n / i) * (n / i);for(int j = 2 * i; j <= n; j += i) f[i] -= f[j];}if(!n) printf("0\n");else printf("%lld\n", f[1] + 2);return 0;
}

能量采集

给一个 n ∗ m n * m nm 的方格,设某格点与点 ( 0 , 0 ) (0,0) (0,0)​ 连线上的点数为 k k k​​,则该点的值为 2 k + 1 2k+1 2k+1,求所有格点的值之和。

我们可以用容斥原理求出 f ( i ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = k ] f(i) = \sum\limits_{i = 1}^{n}\sum\limits_{j = 1}^{m}[gcd(i,j)= k] f(i)=i=1nj=1m[gcd(i,j)=k]​​ 的值,答案就是 ∑ i = 1 n ( 2 ∗ i − 1 ) ∗ f ( i ) \sum\limits_{i=1}^{n}(2*i-1) * f(i) i=1n(2i1)f(i).​​

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll f[N];
int main()
{ll n, m;scanf("%lld%lld", &n, &m);ll ans = 0;for(ll i = min(n, m); i; i--){f[i] = (n / i) * (m / i);for(int j = 2 * i; j <= min(n, m); j += i) f[i] -= f[j];ans += (2 * i - 1) * f[i];}printf("%lld\n", ans);return 0;
}

5. 容斥原理推导欧拉函数

考虑下面的问题:

求欧拉函数 φ ( n ) \varphi(n) φ(n)。其中 φ ( n ) = ∣ { 1 ≤ x ≤ n ∣ gcd ⁡ ( x , n ) = 1 } ∣ \varphi(n)=|\{1\leq x\leq n|\gcd(x,n)=1\}| φ(n)={1xngcd(x,n)=1}​​。

直接计算是 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的,用线性筛是 O ( n ) O(n) O(n) 的,杜教筛是 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32) 的(话说一道数论入门题用容斥做为什么还要扯到杜教筛上),接下来考虑用容斥推出欧拉函数的公式

判断两个数是否互质,首先分解质因数

n = ∏ i = 1 k p i c i n=\prod_{i=1}^k{p_i}^{c_i} n=i=1kpici

那么就要求对于任意 p i p_i pi x x x 都不是 p i p_i pi 的倍数,即 p i ∤ x p_i\nmid x pix. 把它当作属性,对应的集合为 S i S_i Si,因此有

φ ( n ) = ∣ ⋂ i = 1 k S i ∣ = ∣ U ∣ − ∣ ⋃ i = 1 k S i ‾ ∣ \varphi(n)=\left|\bigcap_{i=1}^kS_i\right|=|U|-\left|\bigcup_{i=1}^k\overline{S_i}\right| φ(n)= i=1kSi =U i=1kSi

全集大小 ∣ U ∣ = n |U|=n U=n,而 S i ‾ \overline{S_i} Si 表示的是 p i ∣ x p_i\mid x pix 构成的集合,显然 ∣ S i ‾ ∣ = n p i |\overline{S_i}|=\frac{n}{p_i} Si=pin,并由此推出

∣ ⋂ a i < a i + 1 S a i ∣ = n ∏ p a i \left|\bigcap_{a_i<a_{i+1}}S_{a_i}\right|=\frac{n}{\prod p_{a_i}} ai<ai+1Sai =pain

因此可得

φ ( n ) = n − ∑ i n p i + ∑ i < j n p i p j − ⋯ + ( − 1 ) k n p 1 p 2 ⋯ p n = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p k ) = n ∏ i = 1 k ( 1 − 1 p i ) \begin{split} \varphi(n)=&n-\sum_{i}\frac{n}{p_i}+\sum_{i<j}\frac{n}{p_ip_j}-\cdots+(-1)^k\frac{n}{p_1p_2\cdots p_n}\\ =&n\left(1-\frac{1}{p_1}\right)\left(1-\frac{1}{p_2}\right)\cdots\left(1-\frac{1}{p_k}\right)\\ =&n\prod_{i=1}^k\left(1-\frac{1}{p_i}\right) \end{split} φ(n)===nipin+i<jpipjn+(1)kp1p2pnnn(1p11)(1p21)(1pk1)ni=1k(1pi1)

这就是欧拉函数的数学表示啦

6. D-Double Strings_2021牛客暑期多校训练营5 (nowcoder.com)

组合数学

7. C-Cheating and Stealing_2021牛客暑期多校训练营5 (nowcoder.com)

比较难

8. Necklace of Beads - HDU 6960 - Virtual Judge (vjudge.net)

置换

9. Puzzle loop - HDU 6952 - Virtual Judge (vjudge.net)

高斯消元

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26706.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORCA优化器浅析——​MD Accessor的三级缓存

分析​MD Accessor对元数据的缓存能力 set client_min_messageslog; set optimizer to on; set optimizer_print_optimization_stats to on; --执行SQLoptimizer_print_optimization_stats GUC会打印处ORCA优化器优化流程中的各步骤的统计数据。分析打印日志如下&#xff0c;由…

C++核心编程之函数高级使用

目录 一、函数的默认参数 二、函数占位参数 三、函数重载 四、函数重载-注意事项 一、函数的默认参数 在C中&#xff0c;函数的形参列表中的形参是可以有默认值的 语法&#xff1a;返回值类型 函数名 &#xff08;参数默认值&#xff09;{} 示例1&#xff1a; #includ…

Windows10下ChatGLM2-6B模型本地化安装部署教程图解

随着人工智能技术的不断发展&#xff0c;自然语言处理模型在研究和应用领域备受瞩目。ChatGLM2-6B模型作为其中的一员&#xff0c;以其强大的聊天和问答能力备受关注&#xff0c;并且最突出的优点是性能出色且轻量化。然而&#xff0c;通过云GPU部署安装模型可能需要支付相应的…

在Vitis IDE中使用第三方库 libtiff 保存 tiff 文件

目的和思路 一个Vitis IDE 裸机项目&#xff0c;需要将视频帧无损地保存下来 由于每帧的像素数据是 16bit 1通道的 bayer 格式&#xff0c;满足这一需求的图像格式似乎只有 tiff 格式 开源的tiff 库是 libtiff&#xff0c;而在 Vitis IDE 裸机项目中要使用的话就需要交叉编译…

数据结构day3(2023.7.17)

一、Xmind整理&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;时间复杂度 时间复杂度&#xff1a;只保留最高阶f(n)3*n^2n^2100nT(n)O(3*n^3n^2100n)O(3*n^3)O(n^3)1>O(1):常数阶int ta; 1ab; 1at; 1f(n)3T(n)O(3)O(3*n^0)O(n^0)O(1)2>O(n): 线性阶for…

Python 和 RabbitMQ 进行消息传递和处理

一、RabbitMQ 简介 RabbitMQ 是一个开源的消息代理软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;标准。它的官方客户端提供了多种编程语言的接口&#xff0c;包括 Python、Java 和 Ruby 等。它支持消息的持久化、多种交换机类型、消息通知机制、灵活…

Ubuntu 18.04 Docker 安装配置 Apollo 6.0

百度 Apollo 安装测试&#xff08;1&#xff09; Apollo 6.0 安装完全指南 在这一步出错&#xff1a; 进入到 Apollo 源码根目录&#xff0c;打开终端&#xff0c;执行下述命令以启动 Apollo Docker 开发容器 ./docker/scripts/dev_start.sh并没有成功启动 Apollo docker 开发…

gma 2.0.0a3 (2023.07.17) 更新日志

安装 gma 2.0.0a3 pip install gma2.0.0a3新增 1、为矢量要素&#xff08;Feature&#xff09;添加 【Difference】&#xff08;差集&#xff09;方法   取第一个矢量要素与第二个矢量要素的几何差集。  2、为矢量要素&#xff08;Feature&#xff09;添加几种几何形状测试…

LLaMA(Open and Efficient Foundation Language Models )论文解读(二)

此篇博客主题:LLAMA模型数据、训练时长、功耗及碳排放量 LLaMA: Open and Efficient Foundation Language Models paper https://arxiv.org/pdf/2302.13971v1.pdf 1 训练样本 Overall, our entire training dataset contains roughly 1.4T tokens after tokenization. For mo…

求根节点到叶节点数字之和

给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。 计算从根节点到叶节点生成的 所有数字之和 。…

Ubuntu环境搭建

本文以Ubuntu 18.04为例 安装repo mkdir ~/bin export PATH~/bin:$PATH如果可以访问 google 的地址&#xff0c;下载 Repo 工具&#xff0c;并确保它可执行&#xff1a; curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod ax ~/bin/rep…

left join 和except方法区别和联系

目录 相同点&#xff1a; left join except 不同点 假设有两个表&#xff1a;A客户表 和 B客户表&#xff0c;客户uid是唯一主键 相同点&#xff1a; 查询在A中的客户 但不在B中&#xff0c;也就是图中的阴影部分&#xff0c;left join 和except方法都可以实现 left join …