数位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;
}