zoukankan      html  css  js  c++  java
  • HDU3652 B-number (数位dp)

    对于数位dp,很多人有着不同的板子,我也曾经是使用递推板子,后来发现那种方法太过于灵活,对预处理的思维要求很高,因此在这里讲解一下我这种dfs的板子的通法

    首先最简单的板子是f[][][],表示处理到了前i位,前缀的状态是什么,以及是不是当前位还是受限于最高位

    受限的意思是,比如12345,当我们处理到第5位是,前面四位是1234,这样我们最高只能到5,否则的话到9都是可以的

    这是基本上每道题都要有的三个状态,对于这道题,显然我们还需要两个状态,一个表示前面的数模13的答案是多少,一个表示前面是否已经存在13的情况了

    当递归的结束的时候,我们只需要判断模数是否为0且前面是否已经存在13这种情况即可。这题的前缀肯定是前面是哪个数

    这样就能记忆化搜索了,本题不需要处理前导0,但是有一些题需要处理前导0,我们只需要再给一维状态表示是否还在前导0的数,之后在循环中特判一下就行

    虽然状态看上去很多,但是很多都是2位,并不占多少空间

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<string>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    int f[20][10][14][2][2];
    string s;
    string r;
    int len;
    int sum=13;
    int dfs(int cur,int p1,int r,int m,int flag){
        if(cur==len)
            return m&&(r==0);
        auto &x=f[cur][p1][r][m][flag];
        if(x!=-1)
            return x;
        int v=9;
        if(flag)
            v=s[cur]-'0';
        int ans=0;
        int i;
        for(i=0;i<=v;i++){
            ans+=dfs(cur+1,i,(10*r+i)%sum,m||(i==3&&p1==1),flag&&(i==v));
        }
        return x=ans;
    }
    int solve(string t){
        s=t;
        len=t.size();
        int i;
        memset(f,-1,sizeof f);
        return dfs(0,0,0,0,1);
    }
    int main(){
        while(cin>>r){
            int ans=0;
            ans=solve(r);
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    学习进度——第五周
    构建之法阅读笔记02
    学习进度——第四周
    整型数组——首尾相连
    构建之法阅读笔记01
    二维数组
    学习进度——第三周
    新最大子数组——数量级和数量无限大
    最大子数组求和
    P3388 【模板】割点(割顶)题解 tarjan求割点
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12705893.html
Copyright © 2011-2022 走看看