Square Coins(dp-母函数)

Square Coins

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8307    Accepted Submission(s): 5648


Problem Description
People in Silverland use square coins. Not only they have square shapes but also their values are square numbers. Coins with values of all square numbers up to 289 (=17^2), i.e., 1-credit coins, 4-credit coins, 9-credit coins, ..., and 289-credit coins, are available in Silverland.
There are four combinations of coins to pay ten credits:

ten 1-credit coins,
one 4-credit coin and six 1-credit coins,
two 4-credit coins and two 1-credit coins, and
one 9-credit coin and one 1-credit coin.

Your mission is to count the number of ways to pay a given amount using coins of Silverland.
 

Input
The input consists of lines each containing an integer meaning an amount to be paid, followed by a line containing a zero. You may assume that all the amounts are positive and less than 300.
 

Output
For each of the given amount, one line containing a single integer representing the number of combinations of coins should be output. No other characters should appear in the output.
 

Sample Input
  
  
2 10 30 0
 

Sample Output
  
  
1 4 27
 

Source
Asia 1999, Kyoto (Japan)

题意: 题目给出n的钱数,求有多少种方式找零;

意解:这道题可以用DP做,也可以用母函数做,都是0秒的复杂度,个人觉得DP快点,具体看代码吧!

DP AC代码:

     
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;
typedef long long ll;
ll dp[330];
/****************/
/* 
 * 简单dp问题
 * dp[i]表示可以组成钱数i的方法种数;
 * 状态方程 dp[i] += dp[i - j * j];
 * 表示钱数为i的方法数等于它的所有子区间的方法数的累加;
 */

void unit()
{
    dp[0] = 1; //钱数为0的方法数为1;
    for(int i = 1; i <= 17; i++)
    {
        for(int j = 1; j <= 300; j++)
        {
            if(j - i * i < 0) continue;
            dp[j] += dp[j - i * i];
        }
    }
}

int main()
{
    int n;
    unit();
    while(true)
    {
        scanf("%d",&n);
        if(!n) break;
        printf("%I64d\n",dp[n]);
    }
    return 0;
}

母函数 AC代码:
       
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
typedef long long ll;
const int M  = 1000;
ll a[M],b[M];

int main()
{
    int n;
    while(true)
    {
        scanf("%d",&n);
        if(n == 0) break;
        for(int i = 0; i <= n; i++)
        {
            a[i] = 1;
            b[i] = 0;
        }
        for(int i = 2; i * i <= n; i++)
        {
            int t = i * i;
            for(int j = 0; j <= n; j++)
            {
                for(int k = 0; k + j <= n; k += t)
                {
                    b[k + j] += a[j];
                }
            }
            for(int j = 0; j <= n; j++)
            {
                a[j] = b[j];
                b[j] = 0;
            }
        }
        printf("%I64d\n",a[n]);
    }
    return 0;
}



### C++ 中母函数的使用方法与实现 #### 普通型母函数的概念 普通型母函数是一种数学工具,主要用于解决多重集的组合问题。它通过构造一个多项式函数,使得多项式的各项系数和次数能够反映多重集的特性[^4]。 #### 母函数在 C++ 中的应用场景 母函数通常被用来处理涉及计数的问题,例如硬币面额组合、整数拆分等问题。这些问题可以通过构建对应的母函数并计算其展开形式来求解。以下是具体实现的方式: --- #### 母函数的代码实现 ##### 构造母函数的核心逻辑 母函数的本质是对多个多项式进行逐次相乘的操作。假设我们需要计算若干个多项式的乘积 \( H_1 \times H_2 \times H_3 \ldots \),可以按照如下方式进行模拟: 1. 初始化第一个多项式; 2. 将当前结果逐步与下一个多项式相乘; 3. 循环执行上述操作直至完成所有多项式的运算。 下面是一个具体的 C++ 实现示例,展示如何利用数组存储多项式的系数,并模拟多项式乘法的过程。 ```cpp #include <iostream> #include <vector> using namespace std; // 多项式乘法核心函数 void multiply(vector<int>& res, const vector<int>& poly) { int n = res.size(); int m = poly.size(); // 创建临时变量保存新的多项式结果 vector<int> temp(n + m - 1, 0); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { temp[i + j] += res[i] * poly[j]; } } // 更新结果向量 res = move(temp); } // 主程序入口 int main() { // 假设我们要计算几个多项式的乘积 vector<vector<int>> polynomials = { {1, 1}, {1, 1}, {1, 1} }; // 对应三个二项式 (1+x) // 初始结果为常数项 1 的多项式 vector<int> result = {1}; // 遍历每个多项式并与结果相乘 for (const auto& poly : polynomials) { multiply(result, poly); } // 输出最终结果 cout << "Resulting polynomial coefficients:" << endl; for (size_t i = 0; i < result.size(); ++i) { cout << "Coefficient of x^" << i << ": " << result[i] << endl; } return 0; } ``` --- #### 关键点解析 1. **多项式表示** 在代码中,多项式用一维数组 `vector<int>` 表示,其中索引代表幂次,值代表该幂次前的系数。例如 `[1, 2, 3]` 表示多项式 \( 1 + 2x + 3x^2 \)。 2. **多项式乘法** 使用嵌套循环遍历两个多项式的每一对项,将其乘积累加至目标位置。时间复杂度为 \( O(n \cdot m) \),其中 \( n \) 和 \( m \) 是两多项式的长度。 3. **动态更新结果** 结果多项式随着每次乘法不断扩展,因此需要创建一个新的临时数组来存储中间结果。 --- #### 应用实例 以下是一道经典的题目及其解决方案——给定若干种不同面额的硬币以及它们的数量限制,问总金额为 \( S \) 的方案总数是多少? ```cpp #include <iostream> #include <vector> using namespace std; void multiply(vector<long long>& res, const vector<long long>& poly) { int n = res.size(); int m = poly.size(); vector<long long> temp(n + m - 1, 0); for (int i = 0; i < n; ++i) { for (int j = 0; j < m && i + j < temp.size(); ++j) { temp[i + j] += res[i] * poly[j]; } } res = move(temp); } int main() { int numCoins; cin >> numCoins; vector<pair<int, int>> coins(numCoins); // 存储面额和数量限制 for (auto &coin : coins) { cin >> coin.first >> coin.second; // 输入面额和最大数量 } int targetSum; cin >> targetSum; // 初始化结果多项式 vector<long long> result(1, 1); for (const auto &[value, limit] : coins) { vector<long long> currentPoly(limit + 1, 0); for (int k = 0; k <= limit; ++k) { if (k * value > targetSum) break; currentPoly[k] = 1; } multiply(result, currentPoly); } // 找到目标金额对应的系数 if (targetSum >= result.size()) { cout << "No solution." << endl; } else { cout << "Number of ways to make sum " << targetSum << ": " << result[targetSum] << endl; } return 0; } ``` 此代码实现了基于母函数的方法,解决了硬币组合问题。 --- #### 总结 C++ 中母函数的实现主要依赖于多项式乘法的思想。通过对多项式进行逐层累乘,我们可以高效地解决问题中的组合情况。这种技术广泛应用于 ACM 竞赛以及其他算法领域。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值