【马蹄集】—— 概率论专题:第二类斯特林数

news2024/11/6 19:34:36

概率论专题:第二类斯特林数



目录

  • MT2224 矩阵乘法
  • MT2231 越狱
  • MT2232 找朋友
  • MT2233 盒子与球
  • MT2234 点餐




MT2224 矩阵乘法

难度:黄金    时间限制:5秒    占用内存:128M
题目描述

输入两个矩阵,第一个矩阵尺寸为 l × m l×m l×m ,第二个矩阵尺寸为 m × n m×n m×n ,请你输出这两个矩阵相乘后的结果矩阵。

格式

输入格式:第一行输入三个整数 l , m l,m l,m n n n
      接下来 l l l 行,每行 m m m 个整数,表示第一个矩阵;
     再接下来 m m m 行,每行 n n n 个整数,表示第二个矩阵。
输出格式:输出 l l l 行,每行 n n n 个整数,表示结果矩阵。

样例 1

输入:
4 3 4
1 2 3
4 -5 6
7 8 9
-3 2 1
4 5 6 7
8 6 9 7
0 0 1 0

输出:
20 17 27 21
-24 -10 -15 -7
92 83 123 105
4 -3 1 -7

备注

其中: 1 ≤ l , m , n ≤ 1000 1≤l,m,n≤1000 1l,m,n1000 − 1000 ≤ 矩阵中的元素 ≤ 1000 -1000≤矩阵中的元素≤1000 1000矩阵中的元素1000


相关知识点:线性代数


题解


求解本题只需要知道矩阵乘法的规则即可。设 A A A m × p m×p m×p 的矩阵, B B B p × n p×n p×n 的矩阵,那么矩阵 A A A B B B 可进行乘法运算。设 C = A B C=AB C=AB,则矩阵 C C C 为一个 m × n m×n m×n 的矩阵,且 C C C 的第 i i i 行第 j j j 列元素可被表示为:

C i j = ∑ k = 1 p a i k b k j = a i 1 b 1 j + a i 2 b 2 j + … + a i p b p j C_{ij}=\sum_{k=1}^{p}{a_{ik}b_{kj}}=a_{i1}b_{1j}+a_{i2}b_{2j}+\ldots+a_{ip}b_{pj} Cij=k=1paikbkj=ai1b1j+ai2b2j++aipbpj

如对 A 2 × 3 = [ a 11 a 12 a 13 a 21 a 22 a 23 ] A_{2\times3}=\left[\begin{matrix}a_{11}&a_{12}&a_{13}\\a_{21}&a_{22}&a_{23}\\\end{matrix}\right] A2×3=[a11a21a12a22a13a23] B 3 × 2 = [ b 11 b 12 b 21 b 22 b 31 b 32 ] B_{3\times2}=\left[\begin{matrix}b_{11}&b_{12}\\b_{21}&b_{22}\\b_{31}&b_{32}\\\end{matrix}\right] B3×2= b11b21b31b12b22b32 ,则有:

C 2 × 2 = A B = [ a 11 b 11 + a 12 b 21 + a 13 b 31 a 21 b 11 + a 22 b 21 + a 23 b 31 a 11 b 12 + a 12 b 22 + a 13 b 32 a 21 b 12 + a 22 b 22 + a 23 b 32 ] C_{2\times2}=AB=\left[\begin{matrix}a_{11}b_{11}+a_{12}b_{21}+a_{13}b_{31}&a_{21}b_{11}+a_{22}b_{21}+a_{23}b_{31}\\a_{11}b_{12}+a_{12}b_{22}+a_{13}b_{32}&a_{21}b_{12}+a_{22}b_{22}+a_{23}b_{32}\\\end{matrix}\right] C2×2=AB=[a11b11+a12b21+a13b31a11b12+a12b22+a13b32a21b11+a22b21+a23b31a21b12+a22b22+a23b32]

下面直接给出求解本题的完整代码:

/*
    MT2224 矩阵乘法 
*/ 

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

const int N = 1005;
int mtx1[N][N], mtx2[N][N];

// 输入一个 m*n 的矩阵 
void getMatrix(int m, int n, int matrix[][N])
{
    for(int i=1; i<=m; i++)
        for(int j=1; j<=n; j++)
            cin>>matrix[i][j];
}

// 执行矩阵乘法并打印结果 
void matrixMuiti(int l, int m, int n, int matrix1[][N], int matrix2[][N])
{
    int tmp;
    for(int i=1; i<=l; i++){
        for(int j=1; j<=n; j++){
            tmp = 0;
            for(int k=1; k<=m; k++)
                tmp += matrix1[i][k] * matrix2[k][j];
            cout<<tmp<<" ";
        }
        cout<<endl;
    }
}

int main( )
{
    // 录入数据 
    int l, m, n;cin>>l>>m>>n;
    getMatrix(l ,m, mtx1);
    getMatrix(m, n, mtx2);
    // 执行矩阵乘法并输出结果
    matrixMuiti(l, m, n, mtx1, mtx2);
    return 0;
}


MT2231 越狱

难度:钻石    时间限制:1秒    占用内存:128M
题目描述

监狱有 n n n 个房间,每个房间关押一个犯人,有 m m m 种宗教,每个犯人会信仰其中一种。如果相邻房间中的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱。
答案对1007取模。

格式

输入格式:输入一行只有两个整数,分别代表宗教数 m m m 和房间数 n n n
输出格式:输出一行一个整数代表答案。

样例 1

输入:
2 3

输出:
6

备注

其中: 1 ≤ m ≤ 10 8 , 1 ≤ n ≤ 1010 1\le m\le{10}^8,1≤n≤1010 1m1081n1010


相关知识点:排列组合快速幂


题解


首先对题目的意思进行简单梳理:有 n n n 个并排的人(非环形结构),每个人有且仅有一个信仰,现在有 m m m 种信仰,问相邻两个人具有同一信仰的排列方式有多少种?

“相邻两人具有同一信仰”的排列方式是非常繁杂的,如同信仰的相邻人序列可以取 2、3、……的长度,也可以是中间间隔若干人后出现同信仰的相邻人序列。因此,对这道题采取直接求解法是困难的。此时,我们可以求该事件的对立事件方案数,并用总排列数减去该数即可(总排列数为 m n m^n mn,第 i i i 个人有 m m m 种选择)。

“存在相邻两人具有同一信仰”的对立事件是“任何相邻的人的信仰彼此不同”。在这种情况下,第一个人可以是任意信仰(即 a 1 = m a_1=m a1=m),接下来第二个人只要不和前一个人信仰相同即可(即 a 2 = m − 1 a_2=m-1 a2=m1),第三个人同样只需要和其前一个人的信仰不同(即 a 3 = m − 1 a_3=m-1 a3=m1)……可以发现,后续每个人都只需要满足不和其前一个人的信仰相同即可,即 a i = m − 1 ( i = 2 , 3 , … , n ) a_i=m-1\left(i=2,3,\ldots,n\right) ai=m1(i=2,3,,n)。于是可得到“任何相邻的人的信仰彼此不同”的排列方案共有 ∏ i = 1 n a i = m ( m − 1 ) n − 1 \prod_{i=1}^{n}a_i=m\left(m-1\right)^{n-1} i=1nai=m(m1)n1 种。

所以,“相邻两人具有同一信仰”的排列方案共有 m n − m ( m − 1 ) n − 1 m^n-m\left(m-1\right)^{n-1} mnm(m1)n1 种。

从题目给出的数据范围看,所计算的两个值都非常庞大(无标准的数据类型可以存储),因此答案要求对指定数取模。于是这里就涉及到了模运算的一些性质:

  • 加法: ( a + b ) % M = ( ( a % M ) + ( b % M ) ) \left(a+b\right)\%M=\left(\left(a\%M\right)+\left(b\%M\right)\right)%M (a+b)%M=((a%M)+(b%M))
  • 减法: ( a − b ) % M = ( ( a % M ) − ( b % M ) ) \left(a-b\right)\%M=\left(\left(a\%M\right)-\left(b\%M\right)\right)%M (ab)%M=((a%M)(b%M))
  • 乘法: ( a × b ) % M = ( ( a % M ) × ( b % M ) ) \left(a\times b\right)\%M=\left(\left(a\%M\right)\times\left(b\%M\right)\right)%M (a×b)%M=((a%M)×(b%M))

从模运算的乘法律可以看出,在计算乘幂时,可以边取余边计算,进而降低中间环节求得的数据范围,使标准数据类型可用。

通过循环求乘幂运算的方法很简单,此处主要探讨快速幂的实现。

幂运算 m n m^n mn 有一个特性:每次叠乘时的乘数一致。因此,可通过在已算出的较低次数的乘幂结果上进行新的叠乘运算来降低总计算次数。说简单点就是, m ,   m 2 , ( m 2 ) 2 , … m,\ m^2,\left(m^2\right)^2,\ldots m, m2,(m2)2, 直到 m n m^n mn。这实际上是一种分治的思想,可采用基于递归的方式实现:

int fastPow(int m, int n)
{
    if(n == 1) return m;
    int tmp = fastPow(m, n/2);
    // 幂为奇数 
    if(n&1) return tmp*tmp*m;
    // 幂为偶数 
    else return tmp*tmp;
}

不难看出,采取这种方法实现快速幂的时间复杂度为 O ( l o g 2 n ) O\left({log}_2{n}\right) O(log2n)

另一种基于位运算的快速幂实现方法则从幂的二进制形式出发,通过对幂逐步移位,来实现对幂的分解并完成累乘。例如,对 m 11 m^{11} m11,首先将幂转换为二进制得到 11 10 = 1011 2 = 2 3 + 2 1 + 2 0 {11}_{10}={1011}_2=2^3+2^1+2^0 1110=10112=23+21+20,这说明对乘幂 m 11 m^{11} m11 的计算只需要将其幂 11 计算到 3 次即可。下面用一个实际例子予以说明,计算 m 11 m^{11} m11(初始化乘幂结果为 a n s = 1 ans=1 ans=1,当前底数为 b a s e = m base=m base=m)的流程如下:

  • 取幂 1011 的末位得到 1 说明当前需要进行一次累乘,于是更新 a n s   =   a n s ∗ b a s e   =   m ans\ =\ ans\ast base\ =\ m ans = ansbase = m。在这之后需要更新底数,于是 b a s e   =   b a s e ∗ b a s e   = m 2 base\ =\ base\ast base\ =m^2 base = basebase =m2。最后将幂 1011 向右移一个单位得到 101;
  • 取幂 101 的末位得到 1 说明当前需要进行一次累乘,于是更新 a n s   =   a n s ∗ b a s e   =   m 3 ans\ =\ ans\ast base\ =\ m^3 ans = ansbase = m3。在这之后需要更新底数,于是 b a s e   =   b a s e ∗ b a s e   = m 4 base\ =\ base\ast base\ =m^4 base = basebase =m4 。最后将幂 101 向右移一个单位得到 10;
  • 取幂 10 的末位得到 0 说明当前不需要进行累乘,于是直接更新底数 b a s e   =   b a s e ∗ b a s e   = m 8 base\ =\ base\ast base\ =m^8 base = basebase =m8。最后将幂 10 向右移一个单位得到 1;
  • 取幂 1 的末位得到 1 说明当前需要进行一次累乘,于是更新 a n s   =   a n s ∗ b a s e   =   m 11 ans\ =\ ans\ast base\ =\ m^{11} ans = ansbase = m11。在这之后需要更新底数,于是 b a s e   =   b a s e ∗ b a s e   = m 16 base\ =\ base\ast base\ =m^{16} base = basebase =m16。最后将幂 1 向右移一个单位得到 0;
  • 由于幂已经为 0,故退出算法,输出最终的乘幂结果。

基于位运算的快速幂具有更快的迭代速度,因此在现实中更为常用。下面给出其具体实现(注意,底数 b a s e base base 可以直接在参数 m m m 的基础上直接进行变换,而无需单独设置一个变量):

int fastPow(int m, int n)
{
    int ans = 1;
    while(n){
        if(n&1) ans *= m;
        // 更新底数
        m *= m;
        // 更新幂
        n >>= 1;
    }
    return ans; 
}

对本题而言,由于涉及到的乘幂运算具有较大数据范围,因此需要在求幂的过程中加入取模运算。下面直接给出基于以上思路得到的求解本题的完整代码:

/*
    MT2231 越狱 
    排列问题:m^n - m*(m-1)^(n-1)
*/ 

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

const int MOD = 1007;

// 含取模运算的快速幂模板
int fastPow(long m, long n, long mod)
{
    m %= mod;
    int res = 1;
    while (n){
        if (n & 1)
            res = (res * m) % mod;
        m = (m * m) % mod;
        n >>= 1;
    }
    return res;
}

int main( )
{
    // 录入数据 
    long m, n;cin>>m>>n;    
    // 输出结果(注意为了防止出现负数,需要加上 MOD 后再取模)
    cout<<(fastPow(m, n, MOD)-m*fastPow(m-1, n-1, MOD)%MOD + MOD)%MOD<<endl; 
    return 0;
}


MT2232 找朋友

难度:黄金    时间限制:5秒    占用内存:128M
题目描述

n n n 个人分成 m m m 组,每组至少一人,在比赛结束时,同一组的人两两之间都会成为朋友,不同分组的分组方案得到的朋友对数不同。你的任务是求出最小和最大的朋友对数。

格式

输入格式:两个正整数 n ,   m n,\ m n, m

输出格式:两个整数表示答案。

样例 1

输入:

5 1

输出:

10 10

备注

其中: 1 ≤ m ≤ n ≤ 10 9 1\le m\le n\le{10}^9 1mn109


相关知识点:排列组合


题解


题目让我们将 n n n 个人分进 m m m 个组中,而在同一个组中的所有人都将成为朋友(即任意两人相互认识)。然后题目的要求是:求在给定人和组数情况下的最小朋友数和最大朋友数。

首先要弄清楚朋友数的含义。例如, n n n 个人一组时有多少朋友数?实际上,这个问题等价于: n n n 个顶点最多能形成多少条边?

4个顶点最多能形成多少条边

以某个点为视角,它可以与除自身以外的任何顶点连线得到一条边,因此对这个点而言,它能形成 n − 1 n-1 n1 条边。一共有 n n n 个顶点,则一共能形成 n ( n − 1 ) n\left(n-1\right) n(n1) 条边。但是,由于每条边都有两个顶点,因此在按这样的算法(遍历点)统计边数时所有边都会被额外记录一次。所以 n n n 个顶点最多能形成 n ( n − 1 ) 2 \frac{n\left(n-1\right)}{2} 2n(n1) 条边。

当然,也可以从排列组合的角度来求解。“ n n n 个顶点最多能形成多少条边”等价于“从 n n n 个顶点中选择 2 个顶点有多少种选法?”显然,这个问题的答案是 C n 2 = n ( n − 1 ) 2 C_n^2=\frac{n\left(n-1\right)}{2} Cn2=2n(n1)

而本题有所不同,它要求计算将 n n n 个人分进 m m m 个组时,整个系统内的最小和最大朋友数。那什么时候系统内的朋友数最少,什么时候又最大呢?前面提到单个组内的人数(假设为 x x x )能形成的朋友数为 x ( x − 1 ) 2 \frac{x\left(x-1\right)}{2} 2x(x1)。这是一个关于人数的二次函数,因此其在人数更多的情况下会产生比人数更少时更多的朋友数。所以,为了使整个系统内的朋友数尽可能少,就需要让各个分组内的人数较为平均;为了使整个系统内的朋友数尽可能多,就需要让一个分组得到尽可能多的人,而剩余分组则仅分一人。基于此,可分别有以下结论:

  • 最小朋友数:将 n n n 个人平均分配到 m m m 个组中。则 n % m n\%m n%m 的组会分到 n m + 1 \frac{n}{m}+1 mn+1 个人;剩余 m − n % m m-n\%m mn%m 个组将分到 n m \frac{n}{m} mn(设为 t m p tmp tmp)个人。因此,系统内的总朋友数为: ( n % m ) ∗ C t m p + 1 2 + ( m − n % m ) ∗ C t m p 2 (n\%m)*C_{tmp+1}^2+(m-n\%m)*C_{tmp}^2 (n%m)Ctmp+12+(mn%m)Ctmp2
  • 最大朋友数:将 m − 1 m-1 m1 个人分到 m − 1 m-1 m1 个组中(各组一个人),再将剩余 n − ( m − 1 ) n-(m-1) n(m1) 个人分至最后一个组中。则前面的 m − 1 m-1 m1 个组不会产生朋友数,而剩余一个组将产生 C n − ( m − 1 ) 2 C_{n-(m-1)}^2 Cn(m1)2个朋友数。

下面给出基于以上思路得到的完整代码:

/*
    MT2232 找朋友 
*/ 
#include<bits/stdc++.h> 
using namespace std;

int main( )
{
    // 录入数据 
    int n, m;cin>>n>>m;
    // 最大的朋友对数 
    long tmp = n-(m-1);
    long maxPairs = tmp*(tmp-1)/2;
    // 最小的朋友对数 
    tmp = n / m;
    long minPairs = (m-(n%m))*tmp*(tmp-1)/2 + (n%m)*tmp*(tmp+1)/2;
    // 输出结果
    cout<<minPairs<<" "<<maxPairs<<endl; 
    return 0;
}


MT2233 盒子与球

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

现有 r r r 个互不相同的盒子和 n n n 个互不相同的球,要将这 n n n 个球放入 r r r 个盒子中,且不允许有空盒子。请求出有多少种不同的放法。

两种放法不同当且仅当存在一个球使得该球在两种放法中放入了不同的盒子。

格式

输入格式:输入一行只有两个正整数,分别代表 n n n r r r
输出格式:输出一行一个整数代表答案。

样例 1

输入:
3 2

输出:

6

备注

其中: 1 ≤ r ≤ n ≤ 10 1\le r\le n\le10 1rn10


相关知识点:排列组合第二类斯特林数


题解


这是一道经典的盒子放球问题,简化描述如下: n n n 个不同的球放入 r r r 个不同的盒子,使每个盒子至少有一个球,问总的放置方案。

有关此类问题的一个总结性帖子:n 球放 m 盒子问题汇总。

这实际上是一个集合划分问题,为解决此类问题定义第二类斯特林数 { n m } \begin{Bmatrix}n \\ m\end{Bmatrix} {nm} ,表示将 n n n 个不同元素划分成 m m m 个非空集合(读作 “ n n n 子集 m m m”)。由于该定义是将元素分成若干集合,故又将第二类斯特林数称为斯特林子集数。从该定义不难看出这类数的一些特例:

  • n < m n<m n<m { n m } = 0 \begin{Bmatrix}n \\ m\end{Bmatrix}=0 {nm}=0。因为总存在集合没有任何元素;
  • n ≥ 1 n\geq1 n1 { n 1 } = 0 \begin{Bmatrix}n \\ 1\end{Bmatrix}=0 {n1}=0。因为只有一种划分方案,即将所有元素视为一个集合;
  • n = m  时 n=m\ 时 n=m  { n m } = 1 \begin{Bmatrix}n \\ m\end{Bmatrix}=1 {nm}=1。因为只有一种划分方案,即各元素单独形成一个集合;
  • n ≥ 2 n\geq2 n2 { n 2 } = 2 n − 1 − 1 \begin{Bmatrix}n \\ 2\end{Bmatrix}=2^{n-1}-1 {n2}=2n11。在这种情况下,可将某一元素视为一个集合 Φ \mathrm{\Phi} Φ,其他元素视为另一个集合 Ω \mathrm{\Omega} Ω,接下来对集合 Φ \mathrm{\Phi} Φ 中的 n − 1 n-1 n1 个元素而言,每个元素都有 2 种选择:要么加入集合 Φ \mathrm{\Phi} Φ,要么留在集合 Ω \mathrm{\Omega} Ω 中,因此这将产生 2 n − 1 2^{n-1} 2n1 种组合方案。但是,这里面包含了全部元素都被分至集合 Φ \mathrm{\Phi} Φ 中的情况,因此要再减去 1。

接下来我们讨论第二类斯特林数的递推关系。还是以 “将 n n n 个元素划分成 m m m 个非空集合” 为例,假设现在我们要对第 n n n 个元素进行分配,那么它面对的场景只有两种情况:

  • 前面 n − 1 n-1 n1 个元素形成了 m − 1 m-1 m1 个集合。在这种情况下,要得到 m m m 个非空集合就只能将第 n n n 个元素单独形成一个集合,只有这一种方案,故其总方案数为 { n − 1 m − 1 } \begin{Bmatrix}n-1 \\ m-1\end{Bmatrix} {n1m1}
  • 前面 n − 1 n-1 n1 个元素形成了 m m m 个集合。在这种情况下,第 n n n 个元素可任选一个集合加入,共有 m m m 种选法,故总方案数为 m ∗ { n m } m*\begin{Bmatrix}n \\ m\end{Bmatrix} m{nm}

于是可得到第二类斯特林数的递推关系:

{ n m } = { n − 1 m − 1 } + m { n − 1 m } , n ≥ 1 \begin{Bmatrix}n \\ m\end{Bmatrix}=\begin{Bmatrix}n-1 \\ m-1\end{Bmatrix}+m\begin{Bmatrix}n-1 \\ m\end{Bmatrix},n≥1 {nm}={n1m1}+m{n1m}n1

有了递推关系和初始化条件便能计算第二类斯特林数:

// 第二类斯特林数(递归实现) 
int getStirling(int n, int m)
{
    if(n<m) return 0;
    else if((n==m) || (m==1)) return 1;
    else if(m==2) return pow(2, (n-1))-1;
    else return getStirling(n-1, m-1) + m*getStirling(n-1, m);
}

注意到一点,本题中的球和盒子都是不同的,而第二类斯特林数仅认定元素之间不同(换言之,用第二类斯特林数计算盒子放球问题时,它得到的结果是盒同而球不同)。为此,我们需要在第二类斯特林数的基础之上再乘以盒子的全排列方案数,即有:

m ! { n m } m!\begin{Bmatrix}n \\ m\end{Bmatrix} m!{nm}

这便是将 n n n 个不同球放入 m m m 个不同盒子的总方案数。

下面给出基于以上思路得到的求解本题的完整代码:

/*
    MT2233 盒子与球 
    分球问题、第二类斯特林数 
*/ 

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

// 第二类斯特林数(递归实现) 
int getStirling(int n, int m)
{
    if(n<m) return 0;
    else if((n==m) || (m==1)) return 1;
    else if(m==2) return pow(2, (n-1))-1;
    else return getStirling(n-1, m-1) + m*getStirling(n-1, m);
}
// 阶乘(递归实现)
int getFactorial(int n){
    if(n==1) return 1;
    else return n*getFactorial(n-1);
}

int main( )
{
    // 录入数据 
    int n, r;cin>>n>>r;
    // 输出结果
    cout<<getFactorial(r)*getStirling(n, r)<<endl; 
    return 0;
}


MT2234 点餐

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

小码哥和他的两个朋友一起去吃饭,他们决定每个人先从菜单上选几道菜,然后点三个人都选中的菜。假设菜单中有 n n n 道菜,他们三人分别点了 a ,   b ,   c a,\ b,\ c a, b, c 道菜,小码哥想知道是否有可能不存在三个人都选中的菜。

格式

输入格式:一行,4 个以空格分隔的正整数 n ,   a ,   b ,   c n,\ a,\ b,\ c n, a, b, c 满足 0 < a ,   b ,   c ≤ n ≤ 1000 0<a,\ b,\ c\le n\le1000 0<a, b, cn1000
输出格式:一行,若可能不存三个人都选中的菜就输出 YES,否则输出 NO

样例 1

输入:
5 3 4 4

输出:

NO


相关知识点:排列组合


题解


求解这道题一定要理解题目所说 “是否有可能不存在三人都选中的菜” 的含义。例如,现在有 5 道菜,三个人分别点了 2、3、4 道菜,则我们需要考虑是否存在一种选菜方案使 “不存在三人都选中的菜” 这种局面出现。例如,一种可能的 “巧合” 如下:

在这里插入图片描述

在上面的选菜方案中,没有任何一个菜被三人同时选中,因此对原问题而言,我们的回答是 “YES”。

又比如,现在有 5 道菜,三个人分别点了 2、4、4 道菜,其中有两个人的选菜方案如下:

在这里插入图片描述

接下来对第三个人而言,假设他已经知道了另外两个人的选菜方案(具有上帝视角),则为了使 “不存在三人都选中的菜” 这种局面出现,那他就只能选择 “红烧肉” 和 “青菜汤”。

在这里插入图片描述

因此对原问题而言,在这样假设下的回答依然是 “YES”。从这里可以看出,原问题是一个 “证存在” 的题设,因此我们在求解时要做的假设是这三个人都足够聪明且足够有默契(相当于直接假设他们彼此可交流)。

注意到一件事,如果给第三个人再多增加一道菜(即现在三人点菜数为 3、4、4),则接下来无论怎样安排每个人的选菜方案,始终会存在某个菜被三人都点一次。即,对原问题回答 “NO”。

可以看出,如果要使得 “不存在三人都选中的菜” 的局面出现,相当于每个菜最多会被点两次。考虑极限情况:即每个菜恰好被点两次。在这种情况下,相当于每个人点的菜的总数之和恰好为总菜品的 2 倍(类似于上图中的情况)。基于此,一旦所有人点的菜的总数之和再多出 1,都会使得某个菜会被点 3 次。因此,不难发现该问题的答案仅取决于 “所有人点的菜的总数之和” 与 “菜品总数” 的大小关系。基于此,可得到求解本题的完整代码:

/*
    MT2234 点餐 
*/ 

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

int main( )
{
    // 录入数据 
    int n, a, b, c;
    cin>>n>>a>>b>>c;
    // 输出结果 
    if(a+b+c > 2*n) cout<<"NO"<<endl;
    else cout<<"YES"<<endl;
    return 0;
}

END


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python-嗨格式 之音频转换,ncm转mp3

缘由&#xff1a;本想下载一些歌到车机播放&#xff0c;发现大部分是ncm格式的。 查了下才知道是音乐软件限制了&#xff0c;会员下载的音频文件为.ncm格式&#xff0c;目前只能在网易云音乐APP上播放&#xff0c;不支持在其他音频播放软件或音频设备使用。 百度转换软件&…

Python词语转拼音

使用python写的图形汉语词语转拼音小工具 1)安装库 pip install flet 2)代码 # 声母列表 initial_consonant_list [b, p, m, f, d, t, n, l, g, k, h, j, q, x, zh, ch, sh, r,z, c, s, y, w] # 韵母列表 list_of_vowels [a, o, e, i, u, , ai, ei, ui, ao, ou, iu, ie, e…

MIKE水动力笔记18_如何将dfsu流场模拟结果的数据导出成txt文件

本文目录 前言Step 1 前置工作Step 2 导出相应数据 前言 MIKE的模拟结果dfsu文件的数据是可以导出的&#xff0c;导出格式为xyz&#xff0c;我们也可以将其改后缀改为txt文本格式&#xff0c;其中包含了某一时刻下所有网格坐标点的数据。 Step 1 前置工作 首先&#xff0c;在…

【驱动开发】控制stm32mp157a开发板三盏灯的亮灭

编写应用程序控制三盏灯的亮灭 head.h&#xff1a; #ifndef __HEAD_H__ #define __HEAD_H__typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t;//LED灯的寄存器地址 #define …

unity脚本_力 c#

创建一个脚本 将代码挂载到物体上 取消物体的重力 运行即向z轴运动 加力之后 是否停止是由阻力影响 如果阻力为零 则会一直运动 如果希望就算有阻力也让物体一直动就将加力代码放在Update函数里 using UnityEngine; public class Power : MonoBehaviour{ Rigidbody rigidBo…

SpringBoot 打包与运行

一、SpringBoot 程序打包 1、在Springboot工程 pom文件中&#xff0c;引入 spring-boot-maven-plugin 插件。 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifact…

基于鹈鹕优化的BP神经网络(分类应用) - 附代码

基于鹈鹕优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于鹈鹕优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.鹈鹕优化BP神经网络3.1 BP神经网络参数设置3.2 鹈鹕算法应用 4.测试结果&#xff1a;5.M…

基于蛇优化优化的BP神经网络(分类应用) - 附代码

基于蛇优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于蛇优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.蛇优化优化BP神经网络3.1 BP神经网络参数设置3.2 蛇优化算法应用 4.测试结果&#x…

二零二三充能必读 | 1024程序员狂欢节 —— 掌握前沿技术,探索未知领域

文章目录 I T 技术 ( I T T e c h n o l o g y ) IT技术(IT Technology) IT技术(ITTechnology)▊《 速学Linux&#xff1a;系统应用从入门到精通》▊《Python网络爬虫入门到实战》 人工智能 ( A r t i f i c i a l I n t e l l i g e n c e ) 人工智能(Artificial Intelligence…

【STM32】两个版本MDK搭建和三种调试器的使用

一、Keil MDK4的安装和介绍 1.Keil MDK和Keil C51的关系 1&#xff09;Keil原来是专门做51&#xff0c;后面被ARM收购&#xff0c; 2&#xff09;Keil MDK是Keil C51的另外一个版本。 2.MDK4下载 Keil Embedded Development Tools for Arm, Cortex-M, Cortex-R4, 8051, C166,…

js鼠标点击添加图标并获取图标的坐标值

给这个图片添加摄像头图标&#xff0c;并获取图标的坐标值&#xff0c;也就是图标的css样式是positon:absolute,获取left和top的值。 图片1 思路是这样的&#xff0c;获取这里的长度&#xff0c; 图片2 1.鼠标点击时距浏览器的左边距离和上边距离&#xff0c;相当于(0,0)坐标 …

1024程序员狂欢节 | IT前沿技术、人工智能、数据挖掘、网络空间安全技术

一年一度的1024程序员狂欢节又到啦&#xff01;成为更卓越的自己&#xff0c;坚持阅读和学习&#xff0c;别给自己留遗憾&#xff0c;行动起来吧&#xff01; 那么&#xff0c;都有哪些好书值得入手呢&#xff1f;小编为大家整理了前沿技术、人工智能、集成电路科学与芯片技术、…

关于AIGC研修班学习笔记

AI工具排行&#xff1a; ChatGptMidjourney——绘画AINotion AI——笔记AITome——做PPT的AIpeioriss Palette.fm——调色AIRemove.bg——抠图AIFliki——视频AIAutoDraw——设计AICopilot——编程AI 国内大模型&#xff1a; 阿里通义千问文心一言讯飞星火商汤日日新腾讯混元…

一文拿下HTTP

HTTP HTTP协议 是应用层使用最广泛的协议之一&#xff0c;从浏览器获取到网页&#xff0c;就是基于http 浏览器和服务器之间的交互桥梁 基于传输层的TCP协议来实现的&#xff0c;是一种无状态的应用层协议 为啥是无状态的呢 简化服务器端的处理逻辑&#xff1a;HTTP是无状态…

【调度算法】NSGA III

写在前面&#xff1a;NSGA III算法在数学上比NSGA II算法要复杂得多&#xff0c;尤其是在参考点那里&#xff0c;我也不是看得很明白&#xff0c;所以这篇文章只是尝试梳理下NSGA III的整体改进思路和优势&#xff0c;不对函数、公式、代码之类的细节做过多分析。如有错误&…

【CANoe】文件处理_hex文件读取解析

hex文件里面只有00&#xff0c;01&#xff0c;04三种码。那么我们在解析的时候只需要对这三种不同状态的进行不同的解析即可。 hex文件格式的解析&#xff0c;可阅读&#xff1a;HEX文件格式详解 首先创建一个Block的结构体&#xff0c;根据经验我们知道&#xff0c;一个数据…

gRPC之gRPC转换HTTP

1、gRPC转换HTTP 我们通常把RPC用作内部通信&#xff0c;而使用Restful Api进行外部通信。为了避免写两套应用&#xff0c;我们使用grpc- gateway 把gRPC转成HTTP。服务接收到HTTP请求后&#xff0c;grpc-gateway把它转成gRPC进行处理&#xff0c;然后以JSON 形式返回数据。…

FOC程序算法编写

1、FOC多路PWM驱动 在BLDC电机控制上&#xff0c;6路PWM 控制模式比3路PWM更自由&#xff0c;因为6个半桥式晶体管的每一个都可以单独控制。 &#xff08;1&#xff09;3PWM &#xff08;2&#xff09;6PWM 2、死区时间 开关元器件的和严格意义并不是相同的。IGBT&#xff0c;…

驱动编写LED灯

demo.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include<linux/io.h> #include "head.h" unsigned int major; char kbuf[128] {}; // 定义三个指针指向映射后的虚拟…

vue3.0 + element plus upload文件上传

提供了&#xff0c;文件超过指定个数&#xff0c;页面做了隐藏的效果 记录一下