C++数位DP

数位DP,对应蓝桥云课 二进制问题 代码框架见下

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

#define ll long long
#define maxd 65

//一般情况参数下,1个参数居多,部分情况会有两个参数
//当需要三个参数的时候,就需要修改结构体了
struct DpData {
    ll data0;
    ll data1;
    ll data2;
    static ll K;
    static ll base;
    DpData() : data0(0), data1(0) {
        init();
    }
    void init();
    ll dfsReturn(bool is_leadingZero)const;
    DpData getNextDpData(bool is_leadingZero, int digit) const;
};
#define data0_max maxd
#define data1_max 2
ll dp[maxd][2][2][data0_max][data1_max];
// 1 修改点,通过输入数据进行输入
ll DpData::K = 0;
// 2 修改点,通过题目条件进行修改,二进制就是2,十进制就是10, 也有可能通过数据输入进行输入
ll DpData::base = 2;
// 3 修改点,数据的初始化,确定data0和data1表示的是什么
void DpData::init() {
    data0 = 0;//代表二进制中1的个数
    data1 = 0;//留空不用
}
// 4 修改点 dfs返回值
ll DpData::dfsReturn(bool is_leadingZero)const {
    if (is_leadingZero) {
        return K == 0;
    }
    return data0 == K;
}

// 5 修改点,状态转移的过程
DpData DpData::getNextDpData(bool is_leadingZero, int digit) const {
    DpData ret = *this;
    if (is_leadingZero) {

    }
    else {

    }
    if (digit == 1) {
        ret.data0++;
    }
    return ret;
}

ll dfs(
    const string& num, //数字字符串
    int depth,         //当前枚举到的是第几个数位
    bool is_leadingZero,//默认为true,代表前面枚举的都是0
    bool is_limit, //默认为false,代表前面的所有位都和num相等
    DpData dpdata //数位DP用到的核心数据结构
) {
    if (depth == num.size()) {
        return dpdata.dfsReturn(is_leadingZero);
    }
    int maxdigit = is_limit ? (DpData::base - 1) : (num[depth] - '0');
    ll& ans = dp[depth][is_leadingZero][is_limit][dpdata.data0][dpdata.data1];
    if (ans != -1) {
        return ans;
    }
    ans = 0;
    for (int i = 0; i <= maxdigit; ++i) {
        ans += dfs(
            num,
            depth + 1,
            is_leadingZero && (i == 0),
            is_limit || (i < maxdigit),
            dpdata.getNextDpData(is_leadingZero, i)
        );
    }
    return ans;
}

//固定模版,不需要修改,求[0, n]中所有满足条件的数的数量
ll getans(ll n) {
    memset(dp, -1, sizeof(dp));
    int a[maxd], asize = 0;
    string s;
    while (n) {
        a[asize++] = n % DpData::base;
        n /= DpData::base;
    }
    if (asize == 0) {
        a[asize++] = 0;
    }
    for (int i = asize - 1; i >= 0; --i) {
        s.push_back('0' + a[i]);
    }
    DpData dpd;
    return dfs(s, 0, true, false, dpd);
}

//固定模版,数位DP的差分操作,求[l, r]中所有满足条件的数的个数
ll getans(ll l, ll r) {
    return getans(r) - getans(l - 1);

}
int main()
{
    ll r;
    cin >> r >> DpData::K;
    cout << getans(1, r) << endl;

    // 请在此输入您的代码
    return 0;
}

代码练习 1 长官和他的猫 蓝桥云课 代码见下

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

#define ll long long
#define maxd 65

//一般情况参数下,1个参数居多,部分情况会有两个参数
//当需要三个参数的时候,就需要修改结构体了
struct DpData {
    ll data0;
    ll data1;
    ll data2;
    static ll K;
    static ll base;
    DpData() : data0(0), data1(0) {
        init();
    }
    void init();
    ll dfsReturn(bool is_leadingZero)const;
    DpData getNextDpData(bool is_leadingZero, int digit) const;
};
#define data0_max maxd
#define data1_max 2
ll dp[maxd][2][2][data0_max][data1_max];
// 1 修改点,通过输入数据进行输入
ll DpData::K = 0;
// 2 修改点,通过题目条件进行修改,二进制就是2,十进制就是10, 也有可能通过数据输入进行输入
ll DpData::base = 10;
// 3 修改点,数据的初始化,确定data0和data1表示的是什么
void DpData::init() {
    data0 = 0;//上一位是什么
    data1 = 1;//是否满足给定的条件
}
// 4 修改点 dfs返回值
ll DpData::dfsReturn(bool is_leadingZero)const {
    if (is_leadingZero) {
        return 1;
    }
    return data1;
}

// 5 修改点,状态转移的过程
DpData DpData::getNextDpData(bool is_leadingZero, int digit) const {
    DpData ret = *this;
    if (is_leadingZero) {

    }
    else {
      if(abs(digit - ret.data0) > DpData::K){
        ret.data1 = 0;
      }

    }
    ret.data0 = digit;
    return ret;
}

ll dfs(
    const string& num, //数字字符串
    int depth,         //当前枚举到的是第几个数位
    bool is_leadingZero,//默认为true,代表前面枚举的都是0
    bool is_limit, //默认为false,代表前面的所有位都和num相等
    DpData dpdata //数位DP用到的核心数据结构
) {
    if (depth == num.size()) {
        return dpdata.dfsReturn(is_leadingZero);
    }
    int maxdigit = is_limit ? (DpData::base - 1) : (num[depth] - '0');
    ll& ans = dp[depth][is_leadingZero][is_limit][dpdata.data0][dpdata.data1];
    if (ans != -1) {
        return ans;
    }
    ans = 0;
    for (int i = 0; i <= maxdigit; ++i) {
        ans += dfs(
            num,
            depth + 1,
            is_leadingZero && (i == 0),
            is_limit || (i < maxdigit),
            dpdata.getNextDpData(is_leadingZero, i)
        );
    }
    return ans;
}

//固定模版,不需要修改,求[0, n]中所有满足条件的数的数量
ll getans(ll n) {
    memset(dp, -1, sizeof(dp));
    int a[maxd], asize = 0;
    string s;
    while (n) {
        a[asize++] = n % DpData::base;
        n /= DpData::base;
    }
    if (asize == 0) {
        a[asize++] = 0;
    }
    for (int i = asize - 1; i >= 0; --i) {
        s.push_back('0' + a[i]);
    }
    DpData dpd;
    return dfs(s, 0, true, false, dpd);
}

//固定模版,数位DP的差分操作,求[l, r]中所有满足条件的数的个数
ll getans(ll l, ll r) {
    return getans(r) - getans(l - 1);

}
int main()
{
  ll l, r;
  cin >> l >> r;
  cin >> DpData::K;
  cout << getans(l, r) << endl;
    // 请在此输入您的代码
    return 0;
}

代码练习2 幸运年 对应蓝桥云课 代码见下

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

#define ll long long
#define maxd 65

//一般情况参数下,1个参数居多,部分情况会有两个参数
//当需要三个参数的时候,就需要修改结构体了
struct DpData {
    ll data0;
    ll data1;
    ll data2;
    static ll K;
    static ll base;
    DpData() : data0(0), data1(0) {
        init();
    }
    void init();
    ll dfsReturn(bool is_leadingZero)const;
    DpData getNextDpData(bool is_leadingZero, int digit) const;
};
#define data0_max 1000
#define data1_max 2
ll dp[maxd][2][2][data0_max][data1_max];
// 1 修改点,通过输入数据进行输入
ll DpData::K = 0;
// 2 修改点,通过题目条件进行修改,二进制就是2,十进制就是10, 也有可能通过数据输入进行输入
ll DpData::base = 10;
// 3 修改点,数据的初始化,确定data0和data1表示的是什么
void DpData::init() {
    data0 = 0;//最后一个数位模上1000的值
    data1 = 0;//这三个数是否满足条件
}
// 4 修改点 dfs返回值
ll DpData::dfsReturn(bool is_leadingZero)const {
    if (is_leadingZero) {
        return 0;
    }
    return data1;
}

// 5 修改点,状态转移的过程
DpData DpData::getNextDpData(bool is_leadingZero, int digit) const {
    DpData ret = *this;
    if (is_leadingZero) {

    }
    else {

    }
    if (ret.data0 == 202 && digit == 3) {
        ret.data1 = 1;
    }
    if(ret.data0 % 10 == 1 && digit == 4){
        ret.data1 = 1;
    }
    ret.data0 = (ret.data0 * 10 + digit) % 1000;
    return ret;
}

ll dfs(
    const string& num, //数字字符串
    int depth,         //当前枚举到的是第几个数位
    bool is_leadingZero,//默认为true,代表前面枚举的都是0
    bool is_limit, //默认为false,代表前面的所有位都和num相等
    DpData dpdata //数位DP用到的核心数据结构
) {
    if (depth == num.size()) {
        return dpdata.dfsReturn(is_leadingZero);
    }
    int maxdigit = is_limit ? (DpData::base - 1) : (num[depth] - '0');
    ll& ans = dp[depth][is_leadingZero][is_limit][dpdata.data0][dpdata.data1];
    if (ans != -1) {
        return ans;
    }
    ans = 0;
    for (int i = 0; i <= maxdigit; ++i) {
        ans += dfs(
            num,
            depth + 1,
            is_leadingZero && (i == 0),
            is_limit || (i < maxdigit),
            dpdata.getNextDpData(is_leadingZero, i)
        );
    }
    return ans;
}

//固定模版,不需要修改,求[0, n]中所有满足条件的数的数量
ll getans(ll n) {
    memset(dp, -1, sizeof(dp));
    int a[maxd], asize = 0;
    string s;
    while (n) {
        a[asize++] = n % DpData::base;
        n /= DpData::base;
    }
    if (asize == 0) {
        a[asize++] = 0;
    }
    for (int i = asize - 1; i >= 0; --i) {
        s.push_back('0' + a[i]);
    }
    DpData dpd;
    return dfs(s, 0, true, false, dpd);
}

//固定模版,数位DP的差分操作,求[l, r]中所有满足条件的数的个数
ll getans(ll l, ll r) {
    return getans(r) - getans(l - 1);

}
int main()
{
    ll l, r;
    cin >> l >> r;
    cout << getans(l, r) << endl;
    return 0;
}

代码练习3 对应蓝桥云课 数数问题 代码见下

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

#define ll long long
#define maxd 65

//一般情况参数下,1个参数居多,部分情况会有两个参数
//当需要三个参数的时候,就需要修改结构体了
struct DpData {
    ll data0;
    ll data1;
    ll data2;
    static ll K;
    static ll base;
    DpData() : data0(0), data1(0) {
        init();
    }
    void init();
    ll dfsReturn(bool is_leadingZero)const;
    DpData getNextDpData(bool is_leadingZero, int digit) const;
};
#define data0_max 305
#define data1_max 2
ll dp[maxd][2][2][data0_max][data1_max];
// 1 修改点,通过输入数据进行输入
ll DpData::K = 0;
// 2 修改点,通过题目条件进行修改,二进制就是2,十进制就是10, 也有可能通过数据输入进行输入
ll DpData::base = 2;
// 3 修改点,数据的初始化,确定data0和data1表示的是什么
void DpData::init() {
    data0 = 0;//代表所有数字之和
    data1 = 0;//留空不用
}
// 4 修改点 dfs返回值
ll DpData::dfsReturn(bool is_leadingZero)const {
    if (is_leadingZero) {
        return K == 0 ? 1 : 0;
    }
    return data0 == K;
}

// 5 修改点,状态转移的过程
DpData DpData::getNextDpData(bool is_leadingZero, int digit) const {
    DpData ret = *this;
    if (is_leadingZero) {
      ret.data0 = digit;
    }
    else {
      ret.data0 += digit;
    }
    if (digit == 1) {
        ret.data0++;
    }
    return ret;
}

ll dfs(
    const string& num, //数字字符串
    int depth,         //当前枚举到的是第几个数位
    bool is_leadingZero,//默认为true,代表前面枚举的都是0
    bool is_limit, //默认为false,代表前面的所有位都和num相等
    DpData dpdata //数位DP用到的核心数据结构
) {
    if (depth == num.size()) {
        return dpdata.dfsReturn(is_leadingZero);
    }
    int maxdigit = is_limit ? (DpData::base - 1) : (num[depth] - '0');
    ll& ans = dp[depth][is_leadingZero][is_limit][dpdata.data0][dpdata.data1];
    if (ans != -1) {
        return ans;
    }
    ans = 0;
    for (int i = 0; i <= maxdigit; ++i) {
        ans += dfs(
            num,
            depth + 1,
            is_leadingZero && (i == 0),
            is_limit || (i < maxdigit),
            dpdata.getNextDpData(is_leadingZero, i)
        );
    }
    return ans;
}

//固定模版,不需要修改,求[0, n]中所有满足条件的数的数量
ll getans(ll n) {
    memset(dp, -1, sizeof(dp));
    int a[maxd], asize = 0;
    string s;
    while (n) {
        a[asize++] = n % DpData::base;
        n /= DpData::base;
    }
    if (asize == 0) {
        a[asize++] = 0;
    }
    for (int i = asize - 1; i >= 0; --i) {
        s.push_back('0' + a[i]);
    }
    DpData dpd;
    return dfs(s, 0, true, false, dpd);
}

//固定模版,数位DP的差分操作,求[l, r]中所有满足条件的数的个数
ll getans(ll l, ll r) {
    return getans(r) - getans(l - 1);

}

ll solve(ll a, ll b, ll k){
  ll l = a - 1;
  ll r = b + 1;
  ll lans = getans(a - 1);
  while(l + 1 < r){
    ll mid = (l + r)>>1;
    if(getans(mid) - lans >= k){
      r = mid;
    }else{
      l = mid;
    }
  }
  if(getans(r) - lans >= k){
    return r;
  }
  return -1;
}

int main()
{
  ll l, r, b, m, k;
  cin >> l >> r >> b >> m >> k;
  DpData::base = b;
  DpData::K = m;
  ll ans = solve(l, r, k);
  if(ans == -1){
    cout << "No" << endl;
  }else{
    cout << ans << endl;
  }
    return 0;
}
相关推荐
xhbaitxl2 分钟前
算法学习day39-动态规划
学习·算法·动态规划
I_LPL3 分钟前
day23 代码随想录算法训练营 回溯专题2
算法·hot100·回溯算法·求职面试
智者知已应修善业4 分钟前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
Trouvaille ~9 分钟前
【Linux】应用层协议设计实战(一):自定义协议与网络计算器
linux·运维·服务器·网络·c++·http·应用层协议
CSCN新手听安15 分钟前
【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
linux·运维·服务器·c++·计算机网络·高级io·poll
CSCN新手听安21 分钟前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
m0_7369191021 分钟前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王26 分钟前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法
PPPPPaPeR.1 小时前
光学算法实战:深度解析镜片厚度对前后表面折射/反射的影响(纯Python实现)
开发语言·python·数码相机·算法
看我干嘛!1 小时前
python第五次作业
算法