洛谷 P2347:[NOIP 1996 提高组] 砝码称重 ← 普通母函数

​​【题目来源】
https://www.luogu.com.cn/problem/P2347

【题目描述】
设有 1g、2g、3g、5g、10g、20g 的砝码各若干枚(其总重 ≤1000),可以表示成多少种重量?

【输入格式】
输入方式:a1,a2,a3,a4,a5,a6(表示 1g 砝码有 a1 个,2g 砝码有 a2 个,…,20g 砝码有 a6 个)

【输出格式】
输出方式:Total=N(N 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)

【输入样例】
1 1 0 0 0 0

【输出样例】
Total=3

【数据范围】
总重 ≤1000

【算法分析】
● 对于序列 a₀,a₁,a₂,…,构造函数 G(x) = a₀ + a₁x + a₂x² + … = ∑aₙxⁿ,称为序列 {aₙ} 的普通母函数(Ordinary Generating Function, OGF)。其中 xⁿ 的系数 aₙ 就是要计数的“大小为 n 的方案数”,n∈[0, ∞)。
● 普通母函数只适用于组合问题(顺序无关),不能处理排列问题(顺序有关)。如果要处理排列问题,就要使用指数型母函数 EGF(Exponential Generating Function, EGF),此时 G(x) = ∑aₙxⁿ/n!。

【算法代码】

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

const int MX=1e3+5;
int c1[MX],c2[MX];
int w[]= {1,2,3,5,10,20};
int cnt[6];

int main() {
    for(int i=0; i<6; i++) {
        cin>>cnt[i];
    }

    c1[0]=1; //初始:什么都不选,x^0系数为1
    int curMax=0; //当前多项式最高次
    for(int i=0; i<6; i++) {
        int wi=w[i]; //当前砝码重量
        int ni=cnt[i]; //当前砝码个数
        for(int j=0; j<=curMax; j++) {
            if(c1[j]==0) continue;
            for(int k=0; k<=ni; k++) {
                c2[j+k*wi]+=c1[j];
            }
        }

        //更新当前多项式和最高次
        curMax+=ni*wi;
        for(int j=0; j<=curMax; j++) {
            c1[j]=c2[j];
            c2[j]=0;
        }
    }

    //统计能称出的不同重量(不包括0)
    int ans=0;
    for(int i=1; i<=curMax; i++) {
        if(c1[i]>0) ans++;
    }
    cout<<"Total="<<ans<<endl;

    return 0;
}

/*
in:
1 1 0 0 0 0

out:
Total=3
*/



【参考文献】
https://www.luogu.com.cn/problem/solution/P2347
 

​

posted @ 2026-08-26 22:44  Triwa  阅读(12)  评论(0)    收藏  举报