问题 K: 运动会

题目

题目描述

在一次运会上,有一个比赛项目,共有N个人参加比赛,要将这N个人分组,每组人数不少于K个,问有多少种分组方式?
比如有16个运动员,每组人数不少于5个,共有6种分组方式:
(1) 分一组,为16人;
(2) 分二组,分别为11人、5人;
(3) 分二组,分别为10人、6人;
(4) 分二组,分别为9人、7人;
(5) 分二组,分别为8人、8人;
(6) 分三组,分别为6人、5人、5人。
注意:6+5+5,5+6+5,5+5+6为同一种,只算一种分组方式;

输入

输入共一行为两个整数N, K。表示有N个运动员分组,每组不少于K个人(1 ≤ K ≤ N ≤ 500)。

输出

输出共一行为一个整数,表示分组数。
16 5

6

解析

这个题就是枚举分组,从一个分组到n/m个分组;然后就是每个分组先分上m个,然后就剩下z=n-i*m个球,分到i组里

然后就转化成一个子问题,就是z个球分到 i 个桶里,球相同桶也相同,这是一个dp的问题。传送门

dp[i][j]:将i个球放进j个箱子中,共有多少种不同的放法

dp初始化:
dp[0][j] = 1; 将0个球放进j个箱子中,不管怎么放都只有一种放法(允许空箱)
dp[1][j] = 1; 将1个球放进j个箱子中,不管怎么放都只有一种放法
dp[i][1] = 1; 将i个球放进1个箱子中,不管怎么放都只有一种放法

dp:
当n < m时 dp[i][j] = dp[i][j-1]; 假设将2个球放进3个箱子中和将2个球放进4个箱子中,他们的放法一致
当n >= m时 dp[i][j] = dp[i][j-1] + dp[i-j][j];
其中dp[i][j-1]代表有空箱的情况存在,他的状态可以由空一个箱子转移
dp[i-j][j]代表不空箱的情况,那么至少每个箱子中都要放一个球,那么还剩下i-j个球,然后就变成了i-j个球放进j个箱子中的子问题

 

代码

void init()
{
    for(int i = 0; i < maxn; i++){
        for(int j = 0; j < maxn; j++){
            if(i == 0 || i == 1){
                dp[i][j] = 1;
            }
            if(j == 1){
                dp[i][j] = 1;
            }
        }
    }
}
void solve(){
    init();
    for(int i = 2; i < maxn; i++){
        for(int j = 1; j < maxn; j++){
            if(i < j){
                dp[i][j] = dp[i][j-1];
            }
            else{
                dp[i][j] = dp[i][j-1] + dp[i-j][j];
            }
        }
         
    }
}
int main(){
    solve(); 
    cin>>n>>m;
    int p=n/m;
    __int128 ans=1;
    for(int i=2;i<=p;i++){
        int z=n-i*m;
        if(z==0){
            ans++;
            continue;
        }
        ans+=dp[z][i]; 
    }
    out(ans);
}

 

 

 

posted @ 2021-07-27 10:37  lipu123  阅读(138)  评论(0)    收藏  举报