d624: 燈泡問題
Tags: dp
出處:https://zerojudge.tw/ShowProblem?problemid=d624
提交:https://zerojudge.tw/Submissions?problemid=d624&account=allllllan123456
問題:給你總共 $m\in[1,90]$ 秒燈泡的發亮/熄滅時間,並限定每一段連續熄滅的時間不可超過 $n\in[1,15]$ 秒。請問有多少種亮暗的組合能滿足這個總時間?
解法:這題還是經典 DP,但是稍為不直觀一點。我主要使用的方式是用全部減去不合法,看下面程式碼的註解,由前一組合法的方法數 dp[m-1] 的兩倍 (因為最新秒數可以是亮或暗) 可以得到目前不受限制的總方法數,但是有一種情況需要扣掉,就是最新秒數是暗的時候而且連前面的 n 秒燈泡也都是暗的,這樣是違反規定,只是要注意這樣子的方法數並不是 dp[m-n-1] 而是 dp[m-n-2],因為包含在 dp[m-1] 的方法裡面最多只會有連續 n 秒燈泡是暗的,這暗示了再往前一秒 (m-n-1) 必須是亮的,所以還要再往前一秒 (m-n-2) 才會是自由秒數。另外在初始條件的部分,因為不論那顆必須發亮的燈泡 (m-n-1) 存不存在,都算是 1 種,所以要特別小心。
1#include <bits/stdc++.h>
2using namespace std;
3
4int n;
5long long dp[91];
6
7/* <----------- (m-1) ----------->O
8 * <----------- (m-1) ----------->X
9 * <--- (m-n-2) --->OXXX........XXX
10 * <---- n ---->
11 */
12long long f(int m) {
13 if (m < -1) return 0;
14 if (m <= 0) return 1;
15 if (dp[m]) return dp[m];
16 return dp[m] = 2 * f(m-1) - f(m-n-2);
17}
18
19int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); // IO 優化
20 int m;
21 while (cin >> n >> m) {
22 memset(dp, 0, sizeof dp);
23 cout << f(m) << '\n';
24 }
25 return 0;
26}