当前位置:编程学习 > C/C++ >>

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++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,