zoukankan      html  css  js  c++  java
  • 【hdu3652】数位dp(浅尝ACM-A)

    这里写图片描述
    向大佬学习

    第一次写博客有点紧张,也算是小萌新的突破吧
    这次主要是总结一下校内的ACM比赛的各种题,主要是新思路以及学到的新知识

    先放一张
    这里写图片描述

    下面开始说正事

    题面
    A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string “13” and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.

    Input
    Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).

    Output
    Print each answer in a single line.

    Sample Input
    13
    100
    200
    1000

    Sample Output
    1
    1
    2
    2

    乍眼一看,像极了数位dp,可是怎么判断是否能被13整除呢?之前学过做过的数位dp的限制条件都是有没有包含某数、不包含某数等。这告诉我们需要新思维了。

    我们来回想一下普通的数位dp

    ll dfs(int pos,,bool lead,bool limit)
    {
        if(pos==-1) return 1;
        if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];  
    
        int up=limit?a[pos]:9;
        ll ans=0; 
        for(int i=0;i<=up;i++)
        {  
            if() ...  
            else if()...  
            ans+=dfs(pos-1,,lead && i==0,limit && i==a[pos]) 
        }  
        if(!limit && !lead) dp[pos][state]=ans;  
        return ans;  
    }  

    其实就是记忆化搜索,其中dp[]表示第pos位的state状态,之所以可以直接调用返回,是因为不管前面的位怎么搞,只要符合第pos位的state状态,后面的情况就都定了,所以只需算一次,储存以后直接调用(limit==1要单独计算,以前就在这里挂了)

    那么现在重点来了,state是一个很是重要的突破点,以前的思维就局限在“13”出现过没有,而处理能否被13整除,即为 i mod 13 == 0
    所以dp数组就确定了: dp[i][j][k],i表示第i位,j=0,1,2,j=0表示还没有出现过“13”,j=1表示前一位是“1”,j=2表示已经出现了“13”,k表示当前的数mod13的值。
    转移方程:
    1、j=0,(1)该位为“1”,下传j=1;(2)不为“1”,下传j=0
    2、j=1,(1)“3”,j=2:(2)“1”,j=1;(3)else,j=0;
    3、j=2,直接下传j=2
    4、k=(k*10)% 13(想想为什么)

    然后就显而易见了
    下面放代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    char  a[15];
    int b[15],len;
    int dp[15][3][13];
    
    int dfs(int pos,bool limit,int appr,int mod,bool lead){//注意还要判断前导零的问题
        if(pos==len+1){
            if(appr==2&&mod==0&&lead==0) return 1;
            else return 0;
        }
        if((!limit)&&dp[pos][appr][mod]!=-1) return dp[pos][appr][mod];
        int up=limit?b[pos]:9;
        int ans=0;
        for(int i=0;i<=up;i++){
            if(appr==0){
                if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
                else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
            }
            if(appr==1){
                if(i==3) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
                else if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
                else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
            }
            if(appr==2) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
        }
        if(!limit) dp[pos][appr][mod]=ans;
        return ans;
    }
    int main(){
        while(scanf("%s",a+1)!=EOF){
            len=strlen(a+1);
            for(int i=1;i<=len;i++){
                b[i]=a[i]-'0';
            }
            memset(dp,-1,sizeof(dp));
            int ans=dfs(1,1,0,0,1);
            printf("%d
    ",ans);
        }
        return 0;
    }

    总结:
    对数位dp有了更新的认识,各种不同的限制条件可以化为多个state,state是状态,不只是出现了什么数字而已

  • 相关阅读:
    Windows光标形状
    函数对象(仿函数 functor)
    构造函数的初始化列表抛出异常
    <<Windows via C/C++>>学习笔记 —— 线程优先级【转】
    单例模式
    c++中的重载(Overload)、覆盖(重写,Override) 、隐藏与访问权限控制及using声明
    RTTI: dynamic_cast typeid
    抽象类 虚函数 声明与实现
    typedef 函数指针 数组 std::function
    Client Window坐标 RECT相关函数
  • 原文地址:https://www.cnblogs.com/LinnBlanc/p/7763163.html
Copyright © 2011-2022 走看看