zoukankan      html  css  js  c++  java
  • hdoj4734(数位dp优化)

    题目链接:https://vjudge.net/problem/HDU-4734

    题意:定义一个十进制数AnAn-1...A1的value为An*2n-1+...+A1*20,T组样例(<=1e4),每组样例给出a、b,求出[0,b]中value小于等于a的value的数的个数。

    思路:数位dp,第一能想到将Ai*2i-1的和作为状态,即dp[len][sum]表示到长度为len的数中value为sum的数的个数,最后判断sum<=value(a)来确定是否满足条件。但是问题来了,我们会发现这样的状态与输入a相关,而输入有1e4组,时间限制为500ms,每次还都要memset(dp),显然会超时。

      这个时候就要优化,利用减法,dp[len][sum]表示长度len中value<=sum的数的个数,这一状态性质是所有数共有的性质,与输入a无关,因此可以保存dp的值,而不用memset,最后的结果就是递归到最后一层的sum>=0的数的个数,即value<=value(a)。

    AC代码:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int a[10],dp[10][4700],T;
    
    int gets(int x){
        int k=0,ret=0;
        while(x){
            ret+=(1<<k)*(x%10);
            x/=10;
            k++;
        }
        return ret;
    }
    
    int dfs(int pos,int sum,bool limit){
        if(pos==-1) return 1;
        if(!limit&&dp[pos][sum]!=-1) return dp[pos][sum];
        int up=limit?a[pos]:9;
        int tmp=0;
        for(int i=0;i<=up;++i){
            int t=sum-(1<<pos)*i;
            if(t<0) continue;
            tmp+=dfs(pos-1,t,limit&&i==a[pos]);
        }
        if(!limit) dp[pos][sum]=tmp;
        return tmp;
    }
    
    int solve(int x,int sum){
        int pos=0;
        while(x){
            a[pos++]=x%10;
            x/=10;
        }
        return dfs(pos-1,sum,true);
    }
    
    int main(){
        memset(dp,-1,sizeof(dp));
        scanf("%d",&T);
        for(int i=1;i<=T;++i){
            int a,b,suma;
            scanf("%d%d",&a,&b);
            suma=gets(a);
            printf("Case #%d: %d
    ",i,solve(b,suma));
        }
        return 0;
    }
  • 相关阅读:
    php面试题目
    JavaScript表单处理的返回值问题
    超链接在javascript:void(0)时没有事件响应
    php 两个美元符号:可变变量
    [Ubuntu] lampp安装Zend Framework
    [Ubuntu] 安装字体
    php中bindValue 和 bindParam 的区别
    php遍历文件夹(获得文件名)
    php输出一段字符块
    PHP 全角和半角转换函数
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10753118.html
Copyright © 2011-2022 走看看