zoukankan      html  css  js  c++  java
  • 【HDU3652】B-number-数位DP

    测试地址:B-number

    题目大意:给定一些整数,求以这些整数为n时,区间[0,n]中有多少既含有“13”这个子串又能被13整除的数(称为B数)。

    做法:以前没写过数位DP的记忆化搜索写法,代码风格是向这位大神学习的。记忆化搜索时是从高位到低位搜索,而dp数组的计算是从低位到高位计算的,和迭代写法差不多。dfs函数有五个参数:pos,pre,mod,limit,flag,分别表示当前在第pos位(从低位到高位数),第pos+1位是pre,在这之前构成的数字(为了简便称为s)被13除余数为mod,limit表示当前位有没有被限制,flag表示s中含不含有“13”子串。设dp[i][j][k]为剩下i位数未确定,s被13除余数为j,s特性为k时可能有的B数个数,其中k=0表示s含“13”子串,k=1表示s不含“13”子串但最低位为1,k=2表示s不含“13”子串且最低位不为1。如果走到的状态无法直接用已算出的状态表示,枚举第pos位,注意限制,继续往下搜索。然后注意搜索回来的时候,如果当前位是被限制的,那么不能向dp数组中写入数据,否则根据当前状态的特性向dp数组中写入数据。详情参看代码。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,ans,bit[20];
    int dp[20][20][3];
    
    int dfs(int pos,int pre,int mod,bool limit,bool flag)
    {
      if (pos<=0) return flag&&(mod==0);
      if (!limit&&flag&&dp[pos][mod][0]!=-1) return dp[pos][mod][0];
      if (!limit&&!flag&&pre!=1&&dp[pos][mod][2]!=-1) return dp[pos][mod][2];
      if (!limit&&!flag&&pre==1&&dp[pos][mod][1]!=-1) return dp[pos][mod][1];
      
      int up=limit?bit[pos]:9,ret=0;
      for(int i=0;i<=up;i++)
        ret+=dfs(pos-1,i,(mod*10+i)%13,limit&&(i==up),flag||(pre==1&&i==3));
      
      if (!limit)
      {
        if (flag) dp[pos][mod][0]=ret;
    	if (pre!=1&&!flag) dp[pos][mod][2]=ret;
    	if (pre==1&&!flag) dp[pos][mod][1]=ret;
      }
      
      return ret;
    }
    
    int solve(int n)
    {
      int len=0;
      while(n)
      {
        bit[++len]=n%10;
    	n/=10;
      }
      return dfs(len,0,0,1,0);
    }
    
    int main()
    {
      memset(dp,-1,sizeof(dp));
      while(scanf("%d",&n)!=EOF)
      {
    	printf("%d
    ",solve(n));
      }
      
      return 0;
    }
    


  • 相关阅读:
    梦断代码阅读笔记03
    用户场景分析
    学习进度8
    学习进度7
    梦断代码阅读笔记02
    学习进度6
    随堂小测app(nabcd)
    梦断代码阅读笔记01
    《构建之法》-6
    《构建之法》-5
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793766.html
Copyright © 2011-2022 走看看