/** 傳說中的 “按位dp” 或 “數位dp”。 dp[len][0] 代表數字長度為len不含49的個數 dp[len][1] 代表數字長度為len不含49但是以9開頭的個數(顯然dp[len][1]包含在dp[len][0]中) dp[len][2] 代表數字長度為len含有49的個數 狀態轉移方程如代碼中所示。 然後從n的高位開始統計,其中有一些細節要處理。**/#include<iostream>#include<cstring>#include<cstdio>using namespace std;typedef long long LL;int main(){ LL dp[22][3]; int digit[22]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i=1; i<20; i++) { dp[i][0] = 10*dp[i-1][0] - dp[i-1][1]; // 在dp[i-1][0]前面添上0~9,但是要減去dp[i-1][1] 因為4和9構成49 dp[i][1] = dp[i-1][0]; // 直接在dp[i-1][0]前面添上9就行了 dp[i][2] = 10*dp[i-1][2] + dp[i-1][1]; // 在dp[i-1][2]前面添上0~9,或者在dp[i-1][1]前面添上4 } int t, len; LL n, res; cin >> t; while ( t-- ) { cin >> n; memset(digit, 0, sizeof(digit)); len = 0; while ( n ) { digit[++len] = n%10; n /= 10; } bool flag = false; res = 0; for (int i = len; i >= 1; i--) { res += dp[i-1][2]*digit[i]; if (flag) res += dp[i-1][0]*digit[i]; else if (digit[i] > 4) res += dp[i-1][1]; if (digit[i+1] == 4 && digit[i] == 9) flag = true; } if (flag) res++; // 看別人的代碼都是在輸入n之後就給n+1,不明白為什麼,因為如果把題目中的49改成48,47...那麼n+1也就不管用了, // 我沒有把n+1,而是用判斷flag為真時,res+1,經測試AC,是對的,道理自己想... cout << res << endl; } return 0;}