1. 程式人生 > >Bomb HDU 3555 dp狀態轉移

Bomb HDU 3555 dp狀態轉移

for true 表數 init long cout bool AC 基礎

題目:http://acm.hdu.edu.cn/showproblem.php?pid=3555

題意:

給出一個正整數N,求出1~N中含有數字“49”的數的個數

思路:

采用數位dp的狀態轉移方程法解

具體如下:

dp[len][state]; dp數組的第一位代表數字的位數,第二位代表狀態

狀態設定:

dp[i][0] : i 位數字中不含數字49的數的個數

dp[i][1] : i 位數字中不含數字49,但高位是9的數的個數

dp[i][0] : i 位數字中含有數字49的數的個數

狀態轉移方程:

dp[i][0] = dp[i-1][0] * bit[i] - dp[i-1][1];長度為 i 不含49的數的個數 = 長度為 i-1 中不含49的數的個數*當前數字(因為這個位置可以填0~bit[i]-1),然而,其中包含了bit[i]為4且長度為 i-1 的高位為9,從而組成49····的情況,所以,減去長度為 i-1 的高位為9的數的個數,dp[i-1][1] * 1(這個1代表的是bit[i]為4的情況。

dp[i][1] = dp[i-1][0];長度為 i 的高位為9但不含49的數的個數 = 長度為 i-1 中不含49的數的個數(因為只需在此基礎上加上9即可構成 i 位最高位為9的情況)。

dp[i][2] = dp[i-1][2] * bit[i] + dp[i-1][1];長度為 i 的含有數字49的數的個數 = 長度為 i-1 的個數*當前數字,加上長度為 i-1 的高位為9的數字的個數(加個4就成了i位含49的數了)。

代碼如下:

#include<iostream>
using namespace std;

int n, bit[20];
unsigned long
long dp[20][3], num, ans; void init() { dp[0][0] = 1; for (int i = 1; i < 20; ++i) { dp[i][0] = dp[i - 1][0] * 10 - dp[i - 1][1]; dp[i][1] = dp[i - 1][0]; dp[i][2] = dp[i - 1][2] * 10 + dp[i - 1][1]; } } long long solve() { int len = 0, last = 0; bool flag = false
; num++, ans = 0; while (num) { bit[++len] = num % 10; num /= 10; } for (int i = len; i > 0; --i) { ans += dp[i - 1][2] * bit[i]; if (flag)ans += dp[i - 1][0] * bit[i]; if (!flag&&bit[i] > 4)ans += dp[i - 1][1]; if (last == 4 && bit[i] == 9)flag = true; last = bit[i]; } return ans; } int main() { cin >> n; init(); while (n--) { cin >> num; cout << solve() << endl; } return 0; }

num++的原因是,該方式求的是開區間,而題目為閉區間,所以要+1

感謝您的閱讀,生活愉快~

Bomb HDU 3555 dp狀態轉移