• 数位DP模板


     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 //数位DP一般数据范围很大,所以要开long long 
     5 ll f[now][zt][da];
     6 //now=当前枚举到的数位,一般从高位到低位枚举
     7 //zt=枚举到上一位时的状态,即now+1位
     8 //da=你想要到达的状态
     9 //eg: 比如你想要求一个数能否被它所有数位上的数字整除
    10 //你就可以定义状态为f[当前的数位][上次枚举到的数][之前所有数位的最小公倍数]
    11 //当然,f数组也有可能开到4维,看具体情况
    12 ll num[20];
    13 //num数组记录你要求解的数的每一位上的数字,一般开20就可以了
    14 ll dfs(ll pos,ll state,ll lead,ll limit/*,ll zer 前导0,视情况而定*/){
    15 //pos当前的位数,state上一位的状态,lead想要达到的状态,limit判断前一位是否为最高位
    16 //为什么要判断最高位呢?
    17 /*
    18 我们来举一个例子
    19 比如说我们要求的数为5456
    20 我们把它的千位设为第3位,百位设为第2位,十位设为第1位,个位设为第0位
    21 当它的第三位为0、1、2、3、4时,它的第二位可以从0枚举到9
    22 但是当它的第三位枚举到5时,第二位的数就只能枚举到4
    23 所以我们用一个变量limit记录前一位能不能达到最大值,如果上一位达到了最大值,那么这一位就只能枚举到当前位上的数
    24 如果上一位没有达到最大值,那么这一位就可以从0到9随便枚举
    25 */
    26     if(pos<0){
    27         if(/*满足情况*/)return 1;
    28         else return 0;
    29 } 30 //递归边界,即遍历到了最后一位 31 //这时要结合实际情况判断返回1或0 32 if(!limit && f[pos][state][lead]!=-1) return f[pos][state][lead]; 33 //记忆化 34 //如果当前的f值已经求出来过,并且没有数位限制,那我们就可以直接用 35 //如果有数位限制,那我们就不能直接用,因为我们不知道这两次的数位限制是否相等 36 ll up=limit?num[pos]:9; //枚举上界 37 //如果没有限制,随便遍历 38 //有限制,只能遍历到当前位 39 ll ans=0; //计数 40 for(int i=0;i<=up;i++){ 41 //枚举,然后把不同情况的个数加到ans就可以了 42 ans+=dfs(pos-1,/*状态转移*/nowstate,/*当前的状态,视情况而定*/nowlead, 43 /*想要达到的状态,可能变,也可能不变*/limit && i==up); 44 /*最后一个参数是判断最高位 45 ==的优先级要高于位运算,所以其实就是一个判断当前数字是否为该位上的最大数字的操作 46 如果上一位有限制并且当前枚举到的是该数位上合法的最大的数字,我们就传1,否则传0 47 比如2345 48 当我们的千位上枚举到1,百位上枚举到9时,虽然9是最大的数字。但是第一个条件jud==1并不满足,所以这时我们要传0 49 当我们的千位上枚举到2,百位上枚举到3时,这时两个条件都满足,所以这时我们要传1*/ 50 } 51 if(!limit) f[pos][state][lead]=ans; 52 //如果没有限制,更新f值 53 return ans; 54 //返回结果 55 } 56 ll solve(ll x){ 57 ll tot=0; 58 memset(num,0,sizeof(num)); 59 while(x){ 60 num[tot++]=x%10; 61 x/=10; 62 } 63 //将x的每一位都扔到数组里,方便求解 64 return dfs(tot-1/*传最高位*/,0/*当前的状态,一般是0*/,0/*想要达到的状态,一般也是0,不过要是有取模、除法什么的还要特殊考虑*/ 65 ,1/*上一位数是否达到了最高位,显然达到了,所以传1*/); 66 //有些情况还要判断是不是有前导0,比如统计数字出现的次数,最长上升子序列等等 67 //因为有些情况前导0会对结果造成影响,有些则不会 68 } 69 int main(){ 70 ll a,b; 71 scanf("%lld%lld",&a,&b); 72 //一般都是读入两个数,求区间[a,b]中符合要求的数的个数 73 ll ans=solve(b)-solve(a-1); 74 //一般用差分解决问题 75 printf("%lld ",ans); 76 return 0; 77 }
  • 相关阅读:
    团队作业第四次
    团队作业第三次
    团队作业第二次(2)
    团队作业第二次(1)
    团队作业1
    Pillow库
    pyautogui库
    Python文件读取与异常
    元注解
    Java注解
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/12748823.html
Copyright © 2020-2023  润新知