• 【数位DP】HDU 2089 不要62


    HDU 2089 不要62

    int dp[10][2];
    //dp[i][0]表示当前到哪一位,且前一位不是6
    //dp[i][1]表示当前到哪一位,且前一位是6
    int a[20];
    
    LL dfs(int pos,bool six,bool limit){
    //pos搜到的位置(从高位到低位),lead判断是否有前导零,limit判断是否有最高位限制
        int ans = 0;
        if (pos == -1) return 1;
        //搜到最底部,此时数字为个位数并且跳过了4,满足题意,算1个
        if (!limit && dp[pos][six] != -1) return dp[pos][six];
        //如果没有最高位限制且要用到的dp数组已经更新过,直接返回这个结果
        int end = limit ? a[pos] : 9;
        //决定第pos位所能遍历的数字范围
        //如果有最高位限制,则第pos位数字范围最多到原数字的第pos位数字(如原数字4521,不能算出5xxx来)
        //(注意:虽然拆分数字的时候将各个数位倒着储存了,但dfs时也是倒着来的,两者方向其实一致,所以取的是a[pos])
        for (int i = 0; i <= end; i++) {
            if (i == 4 || six && i == 2) continue;
            //这一位是4,跳过;或者前一位是6且这一位是2,构成62,跳过
            ans += dfs(pos - 1, i == 6, limit && i == end);
            //搜低位的dp结果,如果当前有最高位限制且这一位的数字已经是最大的了,则下一位也有最高位限制
            //(如原数字4521,当前搜到4xxx,则接下来最多45xx,不能是46xx)
        }
        if (!limit) dp[pos][six] = ans;
        //如果没有最高位限制,更新dp数组
        return ans;
        //更新dp数组并将结果返回上一层
    }
    
    LL part(LL x)//把数按位拆分
    {
        int len = 0;
        while (x) {
            a[len++] = x % 10;
            //从a[0]开始,并且是倒着的
            //如1234,在数组中为4321
            x /= 10;
        }
        memset(dp, -1, sizeof dp);
        return dfs(len-1,false,true);
        //从len-1开始,即从x的最高位数字开始
    }
    
    int main()
    {
       ios::sync_with_stdio(false);
       // int t; cin >> t; while (t--)
        LL l, r;
        while(cin>>l>>r)
        {
            if (!l && !r) break;
            cout << part(r) - part(l-1)<<endl;
        }
    
    	return 0;
    }
    
  • 相关阅读:
    【C++】Debugging Segmentation Faults
    Ubuntu硬盘挂载
    基于C++11以及17实现线程池【如何设置线程池大小】
    Ubuntu快速删除大量文件的思路
    基于systemback的Ubuntu系统镜像备份和安装方案
    【Vue项目实践】创建一个 electron+vue3 的项目
    【Vue项目实践】套用github 上的项目(vue3 + Element Plus)运行 可编辑表格
    在vscode中使用博客园插件
    【rtsp】视频流
    【Vue项目实践】采用 iview 快速开始
  • 原文地址:https://www.cnblogs.com/streamazure/p/13046963.html
Copyright © 2020-2023  润新知