每日一題:硬幣

硬幣。給定數量不限的硬幣,幣值爲25分、10分、5分和1分,編寫代碼計算n分有幾種表示法。(結果可能會很大,你需要將結果模上1000000007)

示例1:
輸入: n = 5
輸出:2
解釋: 有兩種方式可以湊成總金額:
5=5
5=1+1+1+1+1

示例2:
輸入: n = 10
輸出:4
解釋: 有四種方式可以湊成總金額:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1

說明:
注意:
你可以假設:
0 <= n (總金額) <= 1000000

/*
方法一:動態規劃(揹包問題)
*/

class Solution {
private:
    static constexpr int mod = 1000000007;
    static constexpr int coins[4] = {25, 10, 5, 1};

public:
    int waysToChange(int n) {
        vector<int> f(n + 1);
        f[0] = 1;
        for (int c = 0; c < 4; c++) {
            int coin = coins[c];
            for (int i = coin; i <= n; i++) {
                f[i] = (f[i] + f[i - coin]) % mod;
            }
        }
        return f[n];
    }
};


/*
數學
對於給定的n,我們先枚舉25分的硬幣的個數i,那麼剩下的部分我們記爲 r = n - 25 * i,r可以表示成:
r = 10 * a + 5 * b + c;
這裏a能取的最大值a0 = r - (r mod 10),當a=a0時限定c < 5可以得到這種情況下b的最大值b0,那麼令
c0 = r - 10 * a0 - 5 * b0;
考慮選擇i個25分硬幣的時候的情況,假設我們選擇x個10分硬幣,那麼還剩下的金額我們可以表示爲:
10 * (a0 - x) + 5 * b0 + c0;
考慮把10 * (a0 - x)這一項全部用5分硬幣來替代,即上面的式子可以轉化成5(2a0 - 2x + b0) + c0,那麼
5分硬幣可以選擇的範圍是[0, 2a0 - 2x + b0],剩下的用1分硬幣補齊。也就是說對於25分取i個,10分取x個
的時候方案總數爲2a0 - 2x + b0 + 1,對x求和:
sum(x=0 ~ a0)(2a0 - 2x + b0 + 1) = (a0 + 1)(a0 + b0 + 1)
我們就可以得到25分取i個的時候的方案總數,枚舉i並累加即可獲得最終的答案。
*/
class Solution {
    static constexpr int mod = 1000000007;
public:
    int waysToChange(int n) {
        int ans = 0;
        for (int i = 0; i * 25 <= n; i++) {
            int rest = n - i * 25;
            int a = rest / 10;
            int b = rest % 10 / 5;
            ans = (ans + (long long)(a + 1) * (a + b + 1) % mod) % mod;
        }
        return ans;
    }
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章