这个题算是数位DP的入门,第一次接触数位DP。自己没有解决出来,参看了好几位大神的博客。直接进入这个问题吧。
首先定义数组DP[i][3],含义如下:
DP[i][0] : 表示最大长度为 i 的数字中不出现 “49”的数字总个数。
DP[i][1]:表示最大长度为 i 的数字中不出现“49”,但是最高位是“9”的数字总个数。
DP[i][2] 表示最大长度为 i 的数字中出现“49”的数字总个数。
题目给出的数字范围最大长度是 19 位(2^63-1).我们首先来计算DP[i][3].显然长度为 1 的数有:DP[1][0]=10,DP[1][1]=1,DP[1][2]=0;计算DP[i][3]的代码如下:
dp[1][0] = 10;
dp[1][1] = 1;
dp[1][2] = 0;
for (i = 2; 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];
}
以上公式:DP[i][0]=DP[i-1][0]×10 - DP[i-1][1] ,这个公式的解释是这样的:在DP[i-1][0] 添加一位数字在最高位有0...9一共10中添加办法,但是当添加的数字是4,若是遇到DP[i-1][1]最高为是9的时候,就会构成“49”.所以需要减去。对于后面两个公式也是这样分析。这样就明白了DP[i][1]其实是DP[i][0]和DP[i][2]之间的纽带。计算完了DP[i][3],下面看看如何统计n.
我们将数字n按从高位到低位来分区统计,比如 n=456:
4 : 0 - 399
5 : 400-449
6 : 450 -455
然后还有 456本身:
再如 n=5693,则分为:
5 : 0 - 4999
6 : 5000 - 5599
9 : 5600 -5689
3: 5690-5692
然后 5693本身。
有一种情况就是数字 n 中本身就含有 “49” ,如 n= 149632,这时候需要特别处理。显然对于 149000 - 149632都是符合条件的数字。
#include<iostream>
using namespace std;
_int64 bit[20];
_int64 dp[20][3];
int main(){
int i,T,len;
_int64 n,ans;
bool flag;
dp[1][0] = 10;
dp[1][1] = 1;
dp[1][2] = 0;
for (i = 2; 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];
}
cin >> T;
while (T--){
ans = 0;
len = 0;
flag = 0;
cin >> n;
while (n){
bit[++len] = n % 10;
n /= 10;
}
bit[len + 1] = 0;
for (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 (bit[i + 1] == 4 && bit[i] == 9)
flag = 1; //n中本身包含49
}
if (flag)
ans++;
cout << ans << endl;
}
return 0;
}