解题思路

这是一个组合数学问题,需要计算满足以下条件的工作分配方案数:

  1. 总共 份工作需要完成
  2. 三位员工分别需要完成 份工作
  3. 每份工作至少有一个人做,可以多个人合作
  4. 不同的工作分配方案或不同的人员组合都算作不同方案

解题步骤:

  1. 首先计算组合数表 ,用于后续计算
  2. 对于第三个人分配的 份工作,我们可以从 份工作中选择
  3. 对于剩下的工作,需要在第一个人和第二个人之间分配
  4. 使用动态规划避免重复计算

代码

#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

算法及复杂度

  • 算法:组合数学 + 动态规划
  • 时间复杂度:,其中 为工作总数
  • 空间复杂度:,用于存储组合数表