• Luogu P2602 [ZJOI2010]数字计数 //数位DP


    数位DP第二题 原题链接

    (话说我打题真的好少 状压好像也就才做了3道 就滚来学数位了= =)

    看题一眼数位DP(这个真的只能看 看不出来也说不了什么)

    数位DP老师教我们的是记忆化DFS写法 好写不爆栈 脑子不迷糊

    特别注意处理前导0 , 数位DP好像难就难在处理前导零上吧 = = 

    爆搜的话想一想要往状态里塞什么东西

    当我们搜完一个数,我们要知道什么时候搜完, 搜完之后这个数能对答案产生多少贡献 , 以及这个数是否合法 , 如何向后推导

    老师已经帮我把这些讲好了......

    long long dfs(int pos , int pre ,int goal, bool limit , bool lead)

    pos 表示现在搜到了第几位, pre表示前面有几个要数的数(原题要求1-9)

    goal 表示现在在数的数 , limit表示受限(这个后面说怎么用和怎么维护), lead表示前导零状态 

    1 pos 搜到第几位不用说, pos从原数长开始,到0结束

      (边界)

    2 pre 表示到这一位之前有几个目标数字(比如23333里面在处理第4位时,前面有2个3)

      用于计算答案

    3 goal 目标数字 原封不动往后传

      用于辅助计算答案

    4 limit 受限 在搜的过程中要注意不能超过原数字大小,那么limit肯定是一个连续的状态, 而且当这一位等于原数当前位的大小时,这个状态接着传递。

      用来判断下一位最高可以取到哪

    5 lead 前导零 如果这一位之前的数都是前导0 那么之前的0 都是不数的

      用于计算0时 排除前导0的干扰

    源代码在下面 结合理解食用

    #include<bits/stdc++.h>
    
    using namespace std ;
    
    long long dp[30][20],cap[30],cnt,n,m;
    
    long long dfs(int pos , int pre ,int goal, bool limit , bool lead){
        if(pos == 0) {
            return pre ;
        }
        if(!limit && !lead && dp[pos][pre] != -1) return dp[pos][pre];
        int upp = (limit) ? cap[pos] : 9 ;
        long long ret = 0;
        for(int i=0; i <= upp; i++){
            ret += dfs(pos-1, ((i==goal) && (!lead || i)) ? pre + 1 : pre, goal, (i==cap[pos] && limit), (i==0 && lead));
        }
        if(!limit && !lead) dp[pos][pre] = ret;
        return ret;
    }
    
    long long solve (int dig,long long x){//注意这里的long long
        memset(cap,0,sizeof cap);
        memset(dp,0xff,sizeof dp);
        cnt=0;
        while (x){
            cnt++;
            cap[cnt]=x%10;
            x/=10;
        }
        return dfs(cnt , 0 , dig ,true ,true);
    }
    
    int main(){
        cin>>n>>m;
        for(int i=0;i<=9;i++){
            cout<<solve(i,m)-solve(i,n-1)<<" ";
        }
        puts ("");
        return 0;
    }

    TAG: SIN_XIII

  • 相关阅读:
    nohup npm start &启动之后关闭终端程序没有后台运行
    C++标准库之string返回值研究
    Apache Thrift的C++多线程编程定式
    实战C++对象模型之成员函数调用
    std::string的拷贝赋值研究
    REdis AOF文件结构分析
    使用Linux自带日志滚动工具logrotate滚动redis日志示例
    源码分析MySQL mysql_real_query函数
    源码解读Linux的limits.conf文件
    C++中的return和exit区别
  • 原文地址:https://www.cnblogs.com/SINXIII/p/10900775.html
Copyright © 2020-2023  润新知