【hdu3555】Bomb 数位dp
題目描述
求 1~N 內包含數位串 “49” 的數的個數。
輸入
The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.
The input terminates by end of file marker.
輸出
For each test case, output an integer indicating the final points of the power.
樣例輸入
3
1
50
500
樣例輸出
0
1
15?
?
題解
數位dp
設 $f[i][j][0/1]$ 表示 $i$ 位數,最高位為 $j$ ,是否包含數位串 “49” 的數的個數。
首先預處理出 $f$ 數組,根據是否以前有“49”或能構成“49”來更新新的 $f$ 值。
然后對于每個詢問跑數位dp:先計算位數不滿 $n$ 的位數的數的答案,然后從高位到低位計算,統計該位小于該數當前位的的數,相等的位考慮下一位。
注意統計當前位時需要同時考慮前面是否有“49”,兩個數位能否拼成“49”,后面是否有“49”。然而本題數字串的第二位是“9”,枚舉時枚舉不到9,因此不需要考慮前后兩個數位拼成“49”的情況。
把詢問轉化為 $[1,n)$ 的區間會更容易些。
代碼中為了避免一些細節(比如 $10^{19}$ 爆long long之類的),使用了unsigned long long。
#include <cstdio> typedef unsigned long long ull; ull f[20][10][2] , b[20]; void init() {int i , j , k , l;f[0][0][0] = b[0] = 1;for(i = 1 ; i < 20 ; i ++ ){b[i] = b[i - 1] * 10;for(j = 0 ; j < 10 ; j ++ )for(k = 0 ; k < 10 ; k ++ )for(l = 0 ; l < 2 ; l ++ )f[i][j][l || (j == 4 && k == 9)] += f[i - 1][k][l];} } ull calc(ull n) {int i , j , di = 1 , flag = 0 , last = 0 , now;ull ans = 0;for(i = 1 ; b[i] <= n ; i ++ )for(j = 1 ; j < 10 ; j ++ )ans += f[i][j][1];for( ; i ; i -- ){now = n / b[i - 1] % 10;for(j = di ; j < now ; j ++ )ans += f[i][j][1] + f[i][j][0] * flag;if(last == 4 && now == 9) flag = 1;di = 0 , last = now;}return ans; } int main() {init();int T;ull n;scanf("%d" , &T);while(T -- ) scanf("%llu" , &n) , printf("%llu\n" , calc(n + 1));return 0; }?
轉載于:https://www.cnblogs.com/GXZlegend/p/7812831.html
總結
以上是生活随笔為你收集整理的【hdu3555】Bomb 数位dp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Serenity安装和创建DEMO--学
- 下一篇: CentOS7下安装ELK三件套