8.数位DP及其衍生

简介: 8.数位DP及其衍生

edde0079b7b746dea74989b8bb5f5c89.png

1.Amount of Degrees(度的数量)

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<bits/stdc++.h>
using namespace std;
const int N=35;
int f[N][N];
int k,b;
void init()
{
    f[0][0]=1;//C00等于1
    for(int i=1;i<N;i++)
        for(int j=0;j<=i;j++)
           f[i][j]=f[i-1][j]+f[i-1][j-1];//利用杨辉三角来求组合数
}
int dp(int n)
{
    if(!n) return 0;//当n等于0时,一种都不符合,所以返回0
    vector<int> a;
    while(n) a.push_back(n%b),n/=b;//否则讲n每一位存进a数组中
    int ans=0,last=0;//ans存的是答案,last存的是当前有多少位是1
    for(int i=a.size()-1;i>=0;i--)//因为存进去的时候倒叙存,所以枚举倒叙枚举每一位
    {
        int x=a[i];//取出该位
        if(x)//因为枚举的是0~x,则该位为0则不枚举
        {
            ans+=f[i][k-last];//当是(0~x)-1时
            if(x==1)//假如该位就是1时,则枚举下一位
            {
                last++;
                if(last>k) break;
            }
            else//否则大与1,则直接加上可以为1的情况
            {
                if(k-last-1>=0) ans+=f[i][k-last-1];
                break;//下一位也不用看了
            }
        }
        if(!i&&k==last) ans++;//假如枚举到最后一位,说明n本身也符合,则ans++
    }
    return ans;
}
int main()
{
    init();//预处理组合数x
   int x,y;
   cin>>x>>y>>k>>b;
   cout<<dp(y)-dp(x-1)<<endl;//求x~y的区间相当于求0~y的减去0~x-的
   return 0;
}


2 数字游戏

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<bits/stdc++.h>
using namespace std;
const int N=35;
int f[N][N];
//预处理的i-1也就是下一步,记住不是前一步
void init()
{
   for(int i=0;i<=9;i++) f[0][i]=1;//独自自己一个也是种合法方案
    for(int i=1;i<N;i++)//枚举位数,从右往左
        for(int j=0;j<=9;j++)//枚举当前位数
            for(int k=j;k<=9;k++)//枚举前一位数的可能
                f[i][j]+=f[i-1][k];
}
int dp(int n)
{
    if(!n) return 1;//当n等于0时,说明这个也是种合法方案
    vector<int> a;
    while(n) a.push_back(n%10),n/=10;//否则讲n每一位存进a数组中
    int ans=0,last=0;//ans存的是答案,last存的是当前最大的末尾数
    for(int i=a.size()-1;i>=0;i--)//因为存进去的时候倒叙存,所以枚举倒叙枚举每一位,也就是从左往右
    {
        int x=a[i];//取出该位
       for(int j=last;j<x;j++) ans+=f[i][j];//当前位要比上一位大才能符合条件
       if(x<last) break;//假如x是不满足大于前一位的,右边分支不用枚举了,不符合条件
        last=x;//则当前最大数更新为x
        if(!i) ans++;//假如枚举到最后一位,说明n本身也符合,则ans++
    }
    return ans;
}
int main()
{
    init();//预处理
   int l,r;
   while(cin>>l>>r) cout<<dp(r)-dp(l-1)<<endl;//求l~r的区间相当于求0~r的减去0~l-1的
   return 0;
}


3 Windy 数

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<bits/stdc++.h>
using namespace std;
const int N=11;
int f[N][N];
//预处理的i-1也就是下一步,记住不是前一步
void init()
{
   for(int i=0;i<=9;i++) f[0][i]=1;//独自自己一个也是种合法方案
    for(int i=1;i<N;i++)//枚举位数,从右往左
        for(int j=0;j<=9;j++)//枚举当前位数
            for(int k=0;k<=9;k++)//枚举前一位数的可能
                if(abs(j-k)>=2)//假如满足条件
                    f[i][j]+=f[i-1][k];
}
int dp(int n)
{
    if(!n) return 0;//n不可能为0,则返回0
    vector<int> a;
    while(n) a.push_back(n%10),n/=10;//否则讲n每一位存进a数组中
    int ans=0,last=-2;//ans存的是答案,last存的是上一位的数,因为要相差大于2,则初始化小于等于-2和大于等于12都可以
    for(int i=a.size()-1;i>=0;i--)//因为存进去的时候倒叙存,所以枚举倒叙枚举每一位,也就是从左往右
    {
        int x=a[i];//取出该位
         for(int j=i==a.size()-1;j<x;j++)//不枚举第一位为0的情况,避免前导0的情况
            if(abs(j-last)>=2)//假如满足条件
             ans+=f[i][j];
        if(abs(x-last)<2) break;//假如下一位不满足条件,则不用枚举下一位,直接跳出
        last=x;//更新上一位为x
        if(!i) ans++;//假如枚举到最后一位,说明n本身也符合,则ans++
    }
    //特殊处理前导0的情况,也就是前几位为0的情况
    for(int i=0;i<a.size()-1;i++)//枚举每个位数
        for(int j=1;j<=9;j++)//枚举该位不能为0
          ans+=f[i][j];
    return ans;
}
int main()
{
   init();//预处理
   int l,r;
   cin>>l>>r;
  cout<<dp(r)-dp(l-1)<<endl;//求l~r的区间相当于求0~r的减去0~l-1的
   return 0;
}


4 数字游戏2

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<bits/stdc++.h>
using namespace std;
const int N=35,M=110;
int P;
int f[N][15][M];
int mod(int a,int b)//因为c++取模会出现负数,这里让模出来是正数
{
    return (a%b+b)%b;
}
//预处理的i-1也就是下一步,记住不是前一步
void init()
{
   for(int i=0;i<=9;i++) f[0][i][i%P]=1;//一个数最高位是自己和mod为自己也是合法
    for(int i=1;i<N;i++)//枚举位数,从右往左
        for(int j=0;j<=9;j++)//枚举第i位的最高位
            for(int k=0;k<P;k++)//枚举第i位模出来的可能
                for(int x=0;x<=9;x++)//枚举i-1位的最高位
                    f[i][j][k]+=f[i-1][x][mod(k-j,P)];//状态计算
}
int dp(int n)
{
    if(!n) return 1;//0模任何数都为0,也是一种合法方案
    vector<int> a;
    while(n) a.push_back(n%10),n/=10;//否则讲n每一位存进a数组中
    int ans=0,last=0;//ans存的是答案,last存的是枚举过的位数的最高位数和
    for(int i=a.size()-1;i>=0;i--)//因为存进去的时候倒叙存,所以枚举倒叙枚举每一位,也就是从左往右
    {
        int x=a[i];//取出该位
         for(int j=0;j<x;j++)//枚举0~x的情况
             ans+=f[i][j][mod(-last,P)];//这里表示前面枚举过的数的mod
        last+=x;//更新枚举过的最高数和
        if(!i&&last%P==0) ans++;//假如枚举到最后一位,说明n本身也符合,则ans++
    }
    return ans;
}
int main()
{
   int l,r;
   while(cin>>l>>r>>P)
  {
      memset(f,0,sizeof f);//清空上一层
      init();//预处理
      cout<<dp(r)-dp(l-1)<<endl;//求l~r的区间相当于求0~r的减去0~l-1的
  }
   return 0;
}

5 不要62

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<bits/stdc++.h>
using namespace std;
const int N=10;
int f[N][N];
//预处理的i-1也就是下一步,记住不是前一步
void init()
{
   for(int i=0;i<=9;i++)//只有一位数的时候都满足,除了4自己
       if(i!=4) f[0][i]=1;
    for(int i=1;i<N;i++)//枚举位数,从右往左
        for(int j=0;j<=9;j++)//枚举第i位的最高位
            if(j!=4)//假如不是4
             for(int k=0;k<=9;k++)//枚举下一位
             {
                if(k==4||j==6&&k==2) continue;//假如不满足条件
                f[i][j]+=f[i-1][k];//否则加上这个方案数
             }
}
int dp(int n)
{
    if(!n) return 1;//0也是一种合法方案
    vector<int> a;
    while(n) a.push_back(n%10),n/=10;//否则讲n每一位存进a数组中
    int ans=0,last=0;//ans存的是答案,last存的是上一位的最高数
    for(int i=a.size()-1;i>=0;i--)//因为存进去的时候倒叙存,所以枚举倒叙枚举每一位,也就是从左往右
    {
         int x=a[i];//取出该位
         for(int j=0;j<x;j++)//枚举0~x的情况
           {
               if(j==4||last==6&&j==2) continue;//假如不满足条件
               ans+=f[i][j];
           }
        if(x==4||last==6&&x==2) break;//假如最高位是4,或者上一位最高数是6当前位是2则直接跳出
        last=x;//更新上一位的最高数
        if(!i&&x!=4) ans++;//假如枚举到最后一位并且最后一位不是4,则n本身也符合
    }
    return ans;
}
int main()
{
   int l,r;
   init();//预处理
   while(cin>>l>>r,l||r) cout<<dp(r)-dp(l-1)<<endl;//求l~r的区间相当于求0~r的减去0~l-1的
   return 0;
}






相关文章
|
6月前
|
机器学习/深度学习 算法 Java
数论中的十个基本概念
数论中的十个基本概念
7 树形DP及其衍生
7 树形DP及其衍生
44 0
|
3月前
|
人工智能 算法
第一周算法设计与分析:C : 200和整数对之间的情缘
这篇文章介绍了解决算法问题"200和整数对之间的情缘"的方法,通过统计数组中每个数模200的余数,并计算每个同余类中数的组合数来找出所有满足条件的整数对(i, j),使得\( A_i - A_j \)是200的整数倍。
6 区间DP及其衍生
6 区间DP及其衍生
44 0
5 状态压缩Dp及其衍生
5 状态压缩Dp及其衍生
66 0
3 背包问题及其衍生
3 背包问题及其衍生
70 0
|
人工智能 BI
二分图及其衍生
二分图及其衍生
60 0
拓扑排序及其衍生
拓扑排序及其衍生
40 0
|
12月前
|
算法
算法学习--数位DP
算法学习--数位DP
|
算法 C++
【每日算法Day 109】五大解法,带你深入了解完全背包方案数
【每日算法Day 109】五大解法,带你深入了解完全背包方案数
102 0