牛客题解 | 工作方案
题目
解题思路
这是一个组合数学问题,需要计算满足以下条件的工作分配方案数:
- 总共 \(s\) 份工作需要完成
- 三位员工分别需要完成 \(a, b, c\) 份工作
- 每份工作至少有一个人做,可以多个人合作
- 不同的工作分配方案或不同的人员组合都算作不同方案
解题步骤:
- 首先计算组合数表 \(C[i][j]\),用于后续计算
- 对于第三个人分配的 \(c\) 份工作,我们可以从 \(s\) 份工作中选择
- 对于剩下的工作,需要在第一个人和第二个人之间分配
- 使用动态规划避免重复计算
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD = 1000000007;
int main() {
    int s, a, b, c;
    while (cin >> s >> a >> b >> c) {
        vector<int> member = {a, b, c};
        sort(member.begin(), member.end());
        
        // 计算组合数表
        vector<vector<int>> C(s + 1, vector<int>(s + 1));
        C[0][0] = 1;
        for (int i = 1; i <= s; i++) {
            C[i][0] = 1;
            for (int j = 1; j <= s; j++) {
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
            }
        }
        
        // 计算方案数
        int left = s - member[2];
        long long ans = 0;
        for (int i = 0; i <= left; i++) {
            if (i <= member[1] && left - i <= member[0]) {
                long long temp = C[member[2]][member[1] - i];
                temp = temp * C[left][i] % MOD;
                temp = temp * C[s - left + i][member[0] - left + i] % MOD;
                ans = (ans + temp) % MOD;
            }
        }
        ans = (ans * C[s][member[2]]) % MOD;
        cout << ans << endl;
    }
    return 0;
}
import java.util.Scanner;
import java.util.Arrays;
public class Main {
    static final int MOD = 1000000007;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int s = sc.nextInt();
            int[] member = new int[3];
            member[0] = sc.nextInt();
            member[1] = sc.nextInt();
            member[2] = sc.nextInt();
            Arrays.sort(member);
            
            // 计算组合数表
            int[][] C = new int[s + 1][s + 1];
            C[0][0] = 1;
            for (int i = 1; i <= s; i++) {
                C[i][0] = 1;
                for (int j = 1; j <= s; j++) {
                    C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
                }
            }
            
            // 计算方案数
            int left = s - member[2];
            long ans = 0;
            for (int i = 0; i <= left; i++) {
                if (i <= member[1] && left - i <= member[0]) {
                    long temp = C[member[2]][member[1] - i];
                    temp = temp * C[left][i] % MOD;
                    temp = temp * C[s - left + i][member[0] - left + i] % MOD;
                    ans = (ans + temp) % MOD;
                }
            }
            ans = (ans * C[s][member[2]]) % MOD;
            System.out.println(ans);
        }
        sc.close();
    }
}
MOD = 1000000007
while True:
    try:
        # 读取输入
        s, a, b, c = map(int, input().split())
        member = sorted([a, b, c])
        
        # 计算组合数表
        C = [[0] * (s + 1) for _ in range(s + 1)]
        C[0][0] = 1
        for i in range(1, s + 1):
            C[i][0] = 1
            for j in range(1, s + 1):
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD
        
        # 计算方案数
        left = s - member[2]
        ans = 0
        for i in range(left + 1):
            if i <= member[1] and left - i <= member[0]:
                temp = C[member[2]][member[1] - i]
                temp = temp * C[left][i] % MOD
                temp = temp * C[s - left + i][member[0] - left + i] % MOD
                ans = (ans + temp) % MOD
        
        ans = (ans * C[s][member[2]]) % MOD
        print(ans)
        
    except EOFError:
        break
算法及复杂度
- 算法:组合数学 + 动态规划
- 时间复杂度:\(\mathcal{O}(s^2)\),其中 \(s\) 为工作总数
- 空间复杂度:\(\mathcal{O}(s^2)\),用于存储组合数表
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号