1

GESP认证C++编程真题解析 | 202312 八级

​欢迎大家订阅我的专栏:算法题解:C++与Python实现
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!

专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。

适合人群:

  • 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
  • 希望系统学习C++/Python编程的初学者
  • 想要提升算法与编程能力的编程爱好者

附上汇总帖:GESP认证C++编程真题解析 | 汇总


编程题

P10112 奖品分配

【题目来源】

洛谷:[P10112 GESP202312 八级] 奖品分配 - 洛谷

【题目描述】

班上有 \(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\) 取模的结果。

【输入样例】

3
3 2 1 2
3 2 1 3
5 3 1 3 1

【输出样例】

3
4
20

【算法标签】

《洛谷 P10112 奖品分配》 #数学# #组合数学# #排列组合# #GESP# #2023#

【代码详解】

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

#define int long long  // 将int重定义为long long
const int N = 1005;     // 最大数组大小
const int mod = 1e9 + 7;  // 模数
int T, n, m;            // T: 测试用例数, n: 总位置数, m: 颜色种类数
int a[N];               // a[i]: 第i种颜色的数量
int c[N][N];            // 组合数C[n][m]
int ans, sum;           // ans: 答案, sum: 所有颜色的总数

// 初始化组合数表(杨辉三角)
void init()
{
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            if (j == 0)
            {
                c[i][j] = 1;  // C(i,0)=1
            }
            else
            {
                // 组合数递推公式:C(i,j)=C(i-1,j)+C(i-1,j-1)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
            }
        }
    }
}

signed main()  // 因为#define int long long,所以用signed main
{
    // 预处理组合数
    init();
    
    // 输入测试用例数
    cin >> T;
    while (T--)
    {
        // 输入总位置数n和颜色种类数m
        cin >> n >> m;
        
        // 初始化总和
        sum = 0;
        
        // 输入每种颜色的数量
        for (int i = 1; i <= m; i++)
        {
            cin >> a[i];
            sum += a[i];  // 计算颜色总数
        }
        
        // 初始化答案为1
        ans = 1;
        int t;  // 可用位置数
        
        // 计算初始可用位置数
        if (sum > n)
        {
            t = n + 1;  // 如果颜色总数超过n,则t=n+1
        }
        else
        {
            t = n;  // 否则t=n
        }
        
        // 计算排列方案数
        for (int i = 1; i <= m; i++)
        {
            // 调试输出
            // cout << "t a[i] " << t << ' ' << a[i] << endl;
            
            // 从t个位置中选择a[i]个位置放第i种颜色
            ans = (ans * c[t][a[i]]) % mod;
            
            // 减少可用位置数
            t -= a[i];
        }
        
        // 输出结果
        cout << ans << endl;
    }
    
    return 0;
}

【运行结果】

3
3 2 1 2
3
3 2 1 3
4
5 3 1 3 1
20
posted @ 2026-01-18 22:13  热爱编程的通信人  阅读(1)  评论(0)    收藏  举报