zoukankan      html  css  js  c++  java
  • SCUT

    https://scut.online/p/249

    数位dp的模板题?

    需要特殊判断0,这个很不优雅,因为0-1=-1是个很奇葩的东西?

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    int a[20];
    ll dp[20][11][3];//不同题目状态不同
    ll dfs(int pos,int eleven,int cnt6,bool lead/*前导零*/,bool limit/*数位上界变量*/)//不是每个题都要判断前导零
    {
        //递归边界,最低位是0,那么pos==-1说明这个数枚举完了
        if(pos==-1)
            return 1;/*这里返回1,表示枚举的这个数是合法的,那么这里就需要在枚举时必须每一位都要满足题目条件,也就是说当前枚举到pos位,一定要保证前面已经枚举的数位是合法的。 */
        //第二个就是记忆化(在此前可能不同题目还能有一些剪枝)
        if(!limit && !lead && dp[pos][eleven][cnt6]!=-1)
            return dp[pos][eleven][cnt6];
        /*常规写法都是在没有限制的条件记忆化,这里与下面记录状态对应*/
        int up=limit?a[pos]:9;//根据limit判断枚举的上界up;这个的例子前面用213讲过了
        ll ans=0;
        //开始计数
        for(int i=0;i<=up;i++)//枚举,然后把不同情况的个数加到ans就可以了
        {
            int new_eleven=(eleven*10+i)%11;
            int new_cnt6=0;
            if(i==6)
                new_cnt6=cnt6+1;
    
            if(pos==0&&new_eleven==0)
                continue;
            if(new_cnt6>=3){
                continue;
            }
    
            ans+=dfs(pos-1,new_eleven,new_cnt6,lead && i==0,limit && i==a[pos]);//最后两个变量传参都是这样写的
            /*这里还算比较灵活,不过做几个题就觉得这里也是套路了
            大概就是说,我当前数位枚举的数是i,然后根据题目的约束条件分类讨论
            去计算不同情况下的个数,还有要根据state变量来保证i的合法性,比如题目
            要求数位上不能有62连续出现,那么就是state就是要保存前一位pre,然后分类,
            前一位如果是6那么这意味就不能是2,这里一定要保存枚举的这个数是合法*/
        }
        //计算完,记录状态
        if(!limit && !lead) dp[pos][eleven][cnt6]=ans;
        /*这里对应上面的记忆化,在一定条件下时记录,保证一致性,当然如果约束条件不需要考虑lead,这里就是lead就完全不用考虑了*/
        return ans;
    }
    
    ll solve(ll x)
    {
        //特殊处理0
        if(x==0)
            return 0;
    
        int pos=0;
        while(x)//把数位分解
        {
            a[pos++]=x%10;//编号为[0,pos),注意数位边界
            x/=10;
        }
    
        return dfs(pos-1/*从最高位开始枚举*/,0,0,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛
    }
    
    int main()
    {
        memset(dp,-1,sizeof(dp));
        //初始化为-1
    
        ll le,ri;
        int cntcase=1;
        while(~scanf("%lld%lld",&le,&ri))
        {
            printf("Case #%d: %lld
    ",cntcase++,solve(ri)-solve(le-1));
        }
    }
  • 相关阅读:
    虚拟设备 ide1:0 将开始断开
    虚拟机集群启动 某一台启动失败
    jeesite1,工具类,文件介绍
    line-clamp
    js中同名的函数的调用情况
    获取子页面iframe的点击事件及iframe跨域的交互
    Docker环境搭建入门
    软件工程课后作业:论我对百度搜索的看法
    第二阶段第十天12.10
    软件工程:用户场景描述
  • 原文地址:https://www.cnblogs.com/Yinku/p/10404043.html
Copyright © 2011-2022 走看看