d702: SOS

Tags: big-number, dp


出處:https://zerojudge.tw/ShowProblem?problemid=d702
提交:https://zerojudge.tw/Submissions?problemid=d702&account=allllllan123456


問題:指定一組哨音總長度 $n\in[1,1000]$ 秒,每個短音持續 1 秒,每個長音持續 2 秒,兩哨音中間休息 1 秒鐘,而且第一秒與最後一秒都不是休息秒。請問有多少種組合能滿足此總長度?


解法:這題也是經典 DP,而且蠻好想的,如果最後一秒鐘是短音,那麼考量到休息秒,要往前推 2 秒才會繼續有哨音;如果最後一秒鐘是長音,也要考量到休息秒,要往前推 3 秒才會繼續有哨音,所以 dp[n] = dp[n-2] + dp[n-3],最後只要注意一下初始條件就好。另外這題因為答案很大,還需要用到大數加法的技巧,程式碼中也有實作。


 1#include <bits/stdc++.h>
 2using namespace std;
 3
 4int length[1001], dp[1001][14]; // 14 * 9 = 126 > 125
 5
 6int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); // IO 優化
 7    for (int i=1; i<=3; i++) { length[i] = dp[i][0] = 1; }
 8    for (int i=4; i<=1000; i++) {
 9        for (int j=0; j<length[i-2]; j++) { // assume length[i-2] >= length[i-3]
10            dp[i][j] += dp[i-2][j] + dp[i-3][j];
11            dp[i][j+1] += dp[i][j] / 1000000000;
12            dp[i][j] %= 1000000000;
13        }
14        length[i] = length[i-2] + (dp[i][length[i-2]] > 0);
15    } int n;
16    while (cin >> n) {
17        cout << dp[n][length[n]-1];
18        for (int i=length[n]-2; i>=0; i--)
19            cout << setfill('0') << setw(9) << dp[n][i];
20        cout << '\n';
21    }
22    return 0;
23}

no image