题意就是求从整数1到N中有多少个含有“49”的数? 比如N=500,那么 "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499",
dp[i][1]=dp[i-1][0]; //在不含49的情况下高位加9
dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; //在含有49的情况下高位随便加一位或者不含49但高位是9,在前面最高位加上4就可以了
so the answer is 15.
先说一下总体思路:
假设统计N=591时,那么按以下的顺序进行统计:
1~499 确定5这一位,统计的数比它小
500~589 确定9这一位 ,统计的数比它小
590 确定1这一位,统计的数比它小
最后判断一下自身是不是符合 即591
循环三次就把符合题意的数的总数全都求出来了,这就是本题的数位DP的奥妙之处.
再比如 1249
1~999
1000~1199
1200~1239
1240~1248
1249
dp[i][j] 表示长度为i的数(也就是有i位数)状态为j的数的总数有多少
本题状态有三种:
①dp[i][0]代表长度为i且不包含49的数有多少个
②dp[i][1]代表长度为i且不包含49且左边第一位(最高位)为9的数有多少个
③dp[i][2]代表长度为i且包含49的数有多少个
打表预处理,0<=i<=21(21位就够了),主要是处理状态的转移
dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; //dp[i][0]高位随便加一个数字都可以,但是会出现49XXX的情况,要减去
对于第i位,说长度为i比较好理解,先加上长度为i-1的所有数中包含49的数,即 ans+=dp[i-1][2]*bit[i]; 为什么乘以bit[i]呢? 比如 bit[i]=5, 那么小于5的数有5种选择,即0,1,2,3,4 ,对于每种选择长度为i-1的数中都有dp[i-1][2]个符合题意的数,所以有 dp[i-1][2]*bit[i] , 所以就求出了第i位比5小的所有数,对于590这个数来说,就是求出了
1~499这些数中一部分有多少符合题意的数。还有i-1位数中如果高位是9,那么第i位只要是4也可以符合题意,所以有了 if(bit[i] >4) ans += dp[i-1][1];
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<stdio.h>
#include<math.h>
#include <string>
#include<string.h>
#include<map>
#include<queue>
#include<set>
#include<utility>
#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define eps 1e-8
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define ll long long int
#define mod 1000000007
#define maxn 11000
#define maxm 10001005
int mi(int a,int b){return a<b?a:b;}
int ma(int a,int b){return a>b?a:b;}
ll dp[21][3];
void init()
{
dp[0][0]=1;
dp[0][1]=dp[0][2]=0;
for(int i=1;i<21;i++){
dp[i][0]=10*dp[i-1][0]-dp[i-1][1];
dp[i][1]=dp[i-1][0];
dp[i][2]=dp[i-1][2]*10+dp[i-1][1];
}
}
int main()
{
int t;
ll n;
rd(t);
init();
while(t--){
scanf("%I64d",&n);
int len=1;
int num[22];
while(n){
num[len++]=n%10;
n/=10;
}
num[len]=0;
ll ans=0;
bool flag=false;
for(int i=len-1;i>=1;i--){
ans+=dp[i-1][2]*num[i];
if(flag) ans+=dp[i-1][0]*num[i];
else if(num[i]>4) ans+=dp[i-1][1];
if(num[i+1]==4&&num[i]==9) flag=true;
}
if(flag) ans++;
printf("%I64d\n",ans);
}
return 0;
}