题目描述
解法一:完全背包(C++)
class Solution {
public:
int waysToChange(int n) {
const int mod = 1e9+7;
vector<int> coins = {1, 5, 10, 25};
vector<int> dp(n+1, 0);
dp[0] = 1;
for(int coin: coins)
{
for(int i=1;i<=n;i++)
{
if(i-coin>=0)
dp[i] = (dp[i]+dp[i-coin])% mod;
}
}
return dp[n];
}
};
解法二:
问题的数学解释是:
求方程 n = 25 a + 10 b + 5 c + d n = 25a+ 10b + 5c + d n=25a+10b+5c+d的非负整数解的个数
注意到25、10、5都是5的整数倍,则可以令 n = 5 m + k , 0 ⩽ k ⩽ 4 n=5m+k,0\leqslant k \leqslant 4 n=5m+k,0⩽k⩽4
于是,
5 m = 20 a + 10 b + 5 c + ( d − k ) 5m=20a+10b+5c+(d-k) 5m=20a+10b+5c+(d−k)
令 e = d − k 5 e=\frac{d-k}{5} e=5d−k,显然 e e e是整数,且与 d d d一一对应。
故,原方程非负整数解的个数等价于方程 m = 5 a + 2 b + c + e m=5a+2b+c+e m=5a+2b+c+e非负整数解的个数,记其为 F ( m ) F(m) F(m)
(i)
a
=
0
a=0
a=0,此时相当于求方程
m
=
2
b
+
c
+
e
m=2b+c+e
m=2b+c+e非负整数解的个数,若记
b
=
i
b=i
b=i,则解的个数为
m
−
2
i
+
1
m-2i+1
m−2i+1,在情况(i)下,总的解的个数为
∑
i
=
0
⌊
m
/
2
⌋
(
m
−
2
i
+
1
)
=
(
⌊
m
/
2
⌋
+
1
)
(
⌊
(
m
+
1
)
/
2
⌋
+
1
)
\sum_{i=0}^{\left \lfloor m/2 \right \rfloor}(m-2i+1)=(\left \lfloor m/2 \right \rfloor+1)(\left \lfloor (m+1)/2 \right \rfloor+1)
∑i=0⌊m/2⌋(m−2i+1)=(⌊m/2⌋+1)(⌊(m+1)/2⌋+1)
(ii)
a
>
0
a>0
a>0,
m
−
5
=
5
(
a
−
1
)
+
2
b
+
c
+
e
=
5
a
′
+
2
b
+
c
+
e
m-5 = 5(a-1)+2b+c+e=5a'+2b+c+e
m−5=5(a−1)+2b+c+e=5a′+2b+c+e,方程解的个数为
F
(
m
−
5
)
F(m-5)
F(m−5)
于是,
F ( m ) = F ( m − 5 ) + ( ⌊ m / 2 ⌋ + 1 ) ( ⌊ ( m + 1 ) / 2 ⌋ + 1 ) F(m)=F(m-5)+(\left \lfloor m/2 \right \rfloor+1)(\left \lfloor (m+1)/2 \right \rfloor+1) F(m)=F(m−5)+(⌊m/2⌋+1)(⌊(m+1)/2⌋+1)
class Solution {
public:
int waysToChange(int n) {
const int mod = 1e9+7;
int ans = 0;
int m = n/5;
while(m>=0)
{
ans = (ans+(long int)(m/2+1)*((m+1)/2+1))%mod;
m -= 5;
}
return ans;
}
};