东华OJ 选课时间

题源:HDU2079

求组合数类型题目。母函数求解。

看了挺多博客都没看懂(可能输入的公式太难看),最后还是看的《算法竞赛入门到进阶》一书看懂了。也写一下作为如同我一样的蒟蒻怎么会用这玩意儿吧。

母函数
定义就不说了。公式为G(x)=(1+x+ x 2 x^2 x2+ ⋯ \cdots )(1+ x 2 x^2 x2+ ⋯ \cdots )(1+ x 3 x^3 x3+ ⋯ \cdots )
如此题中给出的范例,假设需要计算达到40学分的组合数。学分和课数分别为(a,b):(1,1),(2,2),(3,2),(4,2),(5,8),(6,9),(7,6),(8,8)。
那么我们就可以知道1学分的课最少选0节,最多选1节 ⋯ \cdots 依此类推。每一种学分的课都是最少选0节,最多选b节。就可以得到这样的一个计算式。
G(x)=( x 0 ∗ 1 + x 1 ∗ 1 x^{0*1}+x^{1*1} x01+x11)( x 0 ∗ 2 + x 1 ∗ 2 + x 2 ∗ 2 x^{0*2}+x^{1*2}+x^{2*2} x02+x12+x22)( x 0 ∗ 3 + x 1 ∗ 3 + x 2 ∗ 3 x^{0*3}+x^{1*3}+x^{2*3} x03+x13+x23)( x 0 ∗ 4 + x 1 ∗ 4 + x 2 ∗ 4 x^{0*4}+x^{1*4}+x^{2*4} x04+x14+x24)( x 0 ∗ 5 + x 2 ∗ 5 + ⋯ + x 8 ∗ 5 x^{0*5}+x^{2*5}+\cdots+x^{8*5} x05+x25++x85)( ⋯ \cdots );
很明显,在第一个括弧里是1学分课的所有情况:选一次,选两次···以后的每一个括弧同理。
x的次数就是选课的节数*此课的学分。最后的要求的n学分的组合数就是 x n x^n xn的系数。

注意:

母函数运用时若不判断下标是否满足条件会出现下标越界的情况。
若较小的数据,可以直接定义一个很大的数组来防止下标越界。
若较大就必须判断下标是否情况,防止程序崩溃/出错。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int t;
    cin>>t;
    //学n学分 k a b k行,a学分的课有b门
    for(int i=0;i<t;i++){
        int n;
        int k;
        cin>>n>>k;
        int score[9]={0};//最多8分,要从1开始,所以长度9
        int result[50]={0};//保存结果
        int temp[50]={0};//临时存储计算后的
        int a,b;
        for(int j=0;j<k;j++){
            cin>>a>>b;
            score[a]=b;//记录下学分为a的课有b门
        }
        for(int j =0;j<=score[1]&&j<=n;j++){//对初始学分为1的情况进行赋值
            result[j]=1;
        }
        //40 8
        // 1 1
        // 2 2
        // 3 2
        // 4 2
        // 5 8
        // 6 9
        // 7 6
        // 8 8
        //母函数
        for(int now =2;now<=k;now++){//学分为一已经计算过了。
            for(int j = 0;j<=n;j++){//遍历结果
                for(int l=0,m=0;l<=score[now]&&m+j<=n;l++,m+=now){
                        temp[m+j]+=result[j];
                }
            }
            for(int j=0;j<=n;j++){
                result[j]=temp[j];
                temp[j]=0;
            }
        }
        cout<<result[n]<<endl;
    }
    return 0;
}

相同类型的题:HDU 1028。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值