洛谷 P10112 [GESP202312 八级] 奖品分配 题解

PART 1题目描述

题目传送门:洛谷 P10112 GESP202312 八级 奖品分配

题目背景

对应的选择、判断题:https://ti.luogu.com.cn/problemset/1140

题目描述

班上有 \(N\) 名同学,学号从 \(0\) 到 \(N-1\)。有 \(M\) 种奖品要分给这些同学,其中,第 \(i\) 种奖品总共有 \(a_i\) 个 (\(i=0,1, \cdots ,M-1\))。

巧合的是,奖品的数量不多不少,每位同学都可以恰好分到一个奖品,且最后剩余的奖品不超过 \(1\) 个(即:\(N\le a_0+a_1+ \cdots +a_{M-1}\le N+1\))。

现在,请你求出每个班级礼物分配的方案数,所谓方案,指的是为每位同学都分配一个种类的奖品。

只要有一位同学获得了不同种类的奖品,即视为不同的方案。方便起见,你只需要输出方案数对 \(10^{9}+7\) 取模后的结果即可。

共有 \(T\) 个班级都面临着奖品分配的问题,你需要依次为他们解答。

输入格式

第一行一个整数 \(T\),表示班级数量。

接下来 \(T\) 行,每行若干用单个空格隔开的正整数。首先是两个正整数\(N,M\),接着是 \(M\) 个正整数 \(a_0,a_1...a_{M-1}\)。保证 N \\le a_0+a_1+\\cdots+a_{M-1} \\le N+1 。

输出格式

输出 \(T\) 行,每行一个整数,表示该班级分配奖品的方案数对 \(10^{9}+7\) 取模的结果。

输入输出样例 #1

输入 #1

复制代码
3
3 2 1 2
3 2 1 3
5 3 1 3 1 

输出 #1

复制代码
3
4
20

输入输出样例 #2

输入 #2

复制代码
5
100 1 100
100 1 101
20 2 12 8
123 4 80 20 21 3
999 5 101 234 499 66 99

输出 #2

复制代码
1
1
125970
895031741
307187590

说明/提示

样例解释 1

对于第 \(1\) 个班级,学号为 \(0,1,2\) 的同学可以依次分别获得奖品 \(0,1,1\),也可以依次分别获得奖品 \(1,0,1\),也可以依次分别获得奖品 \(1,1,0\) ,因此共有 \(3\) 种方案。

对于第 \(2\) 个班级,学号为 \(0,1,2\) 的同学可以依次分别获得奖品 \(0,1,1\) ,也可以依次分别获得奖品 \(1,0,1\),也可以依次分别获得奖品 \(1,1,0\),也可以依次分别获得奖品 \(1,1,1\),因此共有 \(4\) 种方案。

对于第 \(3\) 个班级,可以把编号为 \(0\) 的奖品分配给 \(5\) 名同学中的任意一名,共有 \(5\) 种方案;再把编号为 \(2\) 的奖品分配给剩余 \(4\) 名同学中的任意一名,共有\(4\) 种方案;最后给剩余 \(3\) 名同学自然获得 \(1\) 号奖品。因此,方案数为 \(5 \times 4 = 20\)。

数据范围

对于 \(30\%\) 的测试点,保证 \(N \le 10\)。

对于另外 \(30\%\) 的测试点,保证 \(M=2\)。

对于所有测试点,保证 \(N \le 1000\);保证 \(T \le 1000\) ;保证 \(M \le 1001\)。

PART 2解题思路

由于题目保证\(S∈\) { n,n+1 },所以可以分两种情况讨论

2.1情况一:\(S=n\)

这时问题等价于:将\(n\)个位置分成\(m\)份,每份有\(a_i\)个位置,求方案数。

这样问题就变成了一个多项式系数问题,公式如下:

\\\boxed{\\binom{N}{a_0,\\ a_1,\\ \\cdots,\\ a_{M-1}} = \\frac{N!}{a_0!\\,a_1!\\,\\cdots\\,a_{M-1}!}} \\

2.2情况二:\(S=n+1\)

这时分完后会多出一个奖品,可以看作丢弃一个奖品后再解决多项式系数问题,公式如下:

\\\boxed{\\text{ans} = \\sum_{i=0}\^{M-1} \\binom{N}{a_0,\\ \\cdots,\\ a_i-1,\\ \\cdots,\\ a_{M-1}} \\cdot \[\\,a_i \\ge 1\\,} \]

化简一下:

\\\boxed{\\begin{aligned} \\text{ans} \&= \\sum_{i=0}\^{M-1} \\binom{N}{a_0,\\ \\cdots,\\ a_i-1,\\ \\cdots,\\ a_{M-1}} \\cdot \[\\,a_i \\ge 1\\, \\4pt &= \sum_{i=0}^{M-1} \frac{N!\cdot a_i}{\prod_{j} a_j!} \\4pt &= \frac{N!}{\prod_{j} a_j!}\sum_{i=0}^{M-1} a_i = \frac{N!\cdot (N+1)}{\prod_{j} a_j!} = \frac{(N+1)!}{\prod_{j} a_j!} \end{aligned}} \]

2.3统一公式

设 \(S=∑a_i\),则:

  • 若\(S=n\):

\\\boxed{\\ \\text{ans} = \\frac{N!}{\\prod_{i=0}\^{M-1} a_i!} \\ } \\

  • 若\(S=n+1\):

\\\boxed{\\ \\text{ans} = \\frac{(N+1)!}{\\prod_{i=0}\^{M-1} a_i!} \\ } \\

即:

\\\boxed{\\ \\text{ans} = \\frac{S!}{\\prod_{i=0}\^{M-1} a_i!} \\ } \\

PART 3算法实现

预处理阶乘\(fact\[\]\)和逆元\(efact\[\]\),对于每一组数据,计算公式为:

\\\boxed{\\text{ans} = fact\[S \times \prod_{i=0}^{M-1} efacta_i \bmod p} \]

代码(c++)

AC CODE

复制代码
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;//模
long long fact[1005];//阶乘
long long efact[1005];//逆元
long long ny(long long a,long long e) {//快速幂函数
    long long res=1;//答案
    while(e>0) {
        if(e%2==1) {
            res=res*a%mod;
        }
        a=a*a%mod;
        e/=2;
    }
    return res;
}
int main() {
    fact[0]=1;
    for(int i=1;i<=1001;i++) {//阶乘预处理
        fact[i]=fact[i-1]*i%mod;
    }
    efact[1001]=ny(fact[1001],mod-2);
    for(int i=1001;i>=1;i--) {//逆元预处理
        efact[i-1]=efact[i]*i%mod;
    }
    long long t;cin>>t;//输入
    while(t--) {
        long long n,m;cin>>n>>m;
        long long a[m+1];//存储a_i
        long long h=0;//S
        for(long long i=1;i<=m;i++) {
            cin>>a[i];
            h+=a[i];//计算S
        }
        long long res=1;//答案
        for(int i=1;i<=m;i++) {
            res=res*efact[a[i]]%mod;//乘积
        }
        cout<<res*fact[h]%mod<<endl;//输出答案
    }
    return 0;
}
/*
注意事项:
1.取模:MOD=1e9+7
2.开long long
3.填充fact[0]和efact[1001]
*/
相关推荐
朝朝辞暮i2 小时前
C++ 第 33 课:事件循环——spin() 到底在干什么
开发语言·c++·算法
殷色玫瑰2 小时前
AVL树:从平衡因子到四种旋转的完整实现
c语言·数据结构·c++·算法·visualstudio
进化中的刀盾兽3 小时前
从零实现 C++ AI 大模型接入 SDK(九):LLMManager 统一模型管理与请求路由
c++
会周易的程序员3 小时前
STVM OSAL 层架构设计文档
c++·物联网·嵌入式·虚拟机·iot·软plc·iec61131
.YM.Z3 小时前
C++——【红黑树】原理详解:定义、性质、插入变色与旋转实现
开发语言·c++
无名猿4 小时前
constexpr 能力扩张:从 C++11 到 C++20 的编译期计算
c++·性能优化·现代c++·编译期
007张三丰4 小时前
C/C++ 内存管理详解:从内存分布到 new/delete 底层原理
java·c语言·c++·内存管理
三月微暖寻春笋5 小时前
【和春笋一起学C++】(七十二)类模板
开发语言·c++·实例·类模板·使用类模板·数组模板
xlq223225 小时前
全面复习4
c++