Hdu 3555 Bomb (DP_数位DP)
题目大意:如果某个数中含有49,那就叫2B数(原来好像不是这个,随便啦).问[0,n]里有几个2B数,n <=2^63 - 1
解题思路:数位DP,和Hdu 3652差不多,但我感觉这题更简单,因为记录的状态更少。这题我用两种方法写过了,其实说两种方法也就是记忆化搜索时传递的参数不一样,核心都是一样的。
第一种:传递三个参数,pos,flag,limit,pos表示当前转移到第几位,flag有三个值(2,1,0)对应着(含有49,不含49但前位是4,前位不是4也不含49),limit表示是否有上限,比如n=1234,现在转移到12,如果下一位选3,那么再下一位就有上限,上限为4,如果不选3,那么下一位就没限制,最高位9,转移能保证转移到数比n小。这样dp数组时2维的。
第二种:这种跑的略慢,但更好理解。传递四个参数,pos,pre,flag,limit,pos和flag的意义一样,pre表示前一位是什么,flag表示是否含49,转移dp数组时3维的。
测试数据:
4
1
50
500
代码:
[cpp]
//第一种写法
#include <stdio.h>
#include <string.h>
#define MAX 1100
#define int64 __int64
int64 digit[30];
int64 dp[30][3],n;
int64 Dfs(int pos,int flag,int limit) {
if (pos == -1) return flag == 2;
if (!limit && dp[pos][flag] != -1)
return dp[pos][flag];
int64 sum = 0;
int end = limit ? digit[pos] : 9;
for (int i = 0; i <= end; ++i) {
int have = flag; //flag == 2 || (flag == 1 && i == 4)
if (flag == 1 && i == 9)
have = 2;
if (flag == 0 && i == 4)
have = 1;
if (flag == 1 && i != 4 && i != 9)
have = 0;
//printf("pos %d flag %d have %d i %d sum %d\n",pos,flag,have,i,sum);
sum += Dfs(pos-1,have,limit&&i==end);
}
if (!limit) dp[pos][flag] = sum;
return sum;
}
int64 Cal(int64 n) {
int pos = 0;
while (n > 0) {
digit[pos] = n % 10;
n /= 10,pos++;
}
return Dfs(pos-1,0,1);
}
int main()
{
int i,j,k,t;
scanf("%d",&t);
while (t--) {
scanf("%I64d",&n);
memset(dp,-1,sizeof(dp));
printf("%I64d\n",Cal(n));
}
}
[cpp]
//第二种写法
#include <stdio.h>
#include <string.h>
#define MAX 1100
#define int64 __int64
int64 digit[30];
int64 dp[30][10][3],n;
int64 Dfs(int pos,int pre,int flag,int limit) {
if (pos == -1) return flag == 1;
if (!limit && dp[pos][pre][flag] != -1)
return dp[pos][pre][flag];
int64 sum = 0;
int end = limit ? digit[pos] : 9;
for (int i = 0; i <= end; ++i) {
if (pre == 4 && i == 9)
sum += Dfs(pos-1,i,1,limit && end == i);
else sum += Dfs(pos-1,i,flag,limit && end == i);
}
if (!limit) dp[pos][pre][flag] = sum;
return sum;
}
int64 Cal(int64 n) {
int pos = 0;
while (n > 0) {
digit[pos] = n % 10;
n /= 10,pos++;
}
//printf("%d\n",pos);
int64 ans = Dfs(pos-1,-1,0,1);
return ans;
}
int main()
{
int i,j,k,t;
scanf("%d",&t);
while (t--) {
scanf("%I64d",&n);
memset(dp,-1,sizeof(dp));
printf("%I64d\n",Cal(n));
}
}
作者:woshi250hua
补充:软件开发 , C++ ,