Blue Bridge Cup - Digital DP

  • The reference video
    is highly recommended
  • What is digital dp
    ? Digital dp is a special kind of dynamic programming. The memorandum method (dfs+record) is often used to deal with the problem of digital dp. The digit dp is a violent enumeration of each digit of the integer. In the process of enumeration, use dp[i][j] to record the possibility of enumeration, so as to avoid repetition
  • Problems that can be solved by digital dp
    Digital dp has a single type of question, and generally speaking, digital dp is used for solving 求取区间[l,r]中满足某个条件P(i)的数字的个数,l和r很大,一般为数十亿. Basically seeing the above conditions means that the question is a digital dp
  • The basic idea of ​​digital dp
    The templates of digital dp are fixed, all the questions can use the same set of templates, just change the number. For convenience, we often use the memorandum method to deal with digital dp. The processing steps are as follows
    1. Divide the interval [l,r]into [1,l-1]and [1,r]. [l,r]At this time , the number of numbers satisfying the condition in the solution is the solution[0,r]-[0,l-1]
    2. Enumerate each bit of the number starting from the highest bit i, and use depth-first traversal to list all the numbers in [0,r]and and record the number of numbers that meet the conditions[0,l-1]
    3. Memory optimization, violent enumeration of each number in 2, some combinations are repeated during the enumeration process, we can use dp to store these repeated combinations.
    4. Use 23 to calculate [1,r]and [1,l-1]directly subtract to get the final result
  • Digital dp frequently asked questions
    1. Digital dp generally has a large data space and cannot use an array to store the state. Generally, 嵌套哈希表the storage state is usedmap<int,map<int,int>>
    2. When enumerating r and l-1, initialize the state before enumerating
  • Core code
    The core code of digital dp is dfs. dfs is universal, and the same set of dfs can be used for each digital dp problem, just change the parameters.
    The state of digital dp is generally all parameters in dfs except bool type. The specific situation and specific analysis, but the state is definitely a parameter in dfs.
  • Template
    P6218 [USACO06NOV] Round Numbers S
#include <iostream> 
#include <algorithm>
#include <bits/stdc++.h>
#include <map>
#include <queue>
using namespace std;
int n;
int l;
int r;
//a为l-1的二进制 
vector<int> a;
//b为r的二进制 
vector<int> b;
map<int,map<int,map<int,int>>> dp;
void init(int x,vector<int> &m){
    
    
	//给定x
	while(x!=0){
    
    
		m.push_back(x%2);
		x=x>>1;
	}
} 
//数位dp常用dfs解决 
int dfs(int t,int pos,int num0,int num1,bool flag,bool lead,vector<int> &roundNum){
    
    
	//pos表示位数,num0表示0个数,num1表示1个数,flag表示前面是否全部到顶
	//lead表示是否为前缀0
	if(pos<0){
    
    
		if(num0>=num1) 	return 1;
		else			return 0;
	}
	//dp[pos][num0][num1]表示在插入第pos位时,前面pos+1~MAX位的0和1数分别为num0和num1时最终所能构成的round number数
	//当flag为false时0~pos位的取值都是0和1
	if(!flag&&dp[pos][num0][num1]!=-1) return dp[pos][num0][num1];
	//确定当前位的填充上限 
	int maxNum=0; 
	if(flag)	maxNum=roundNum[pos];
	else		maxNum=1;
	int ret=0;
	for(int i=0;i<=maxNum;i++){
    
    
		if(i==0){
    
    
			//前导0直接略去 
			if(lead){
    
    
				ret+=dfs(t,pos-1,num0,num1,flag&&(i==maxNum),true,roundNum);
			}else{
    
    
				//当前0不是前导0
				num0++;
				ret+=dfs(t,pos-1,num0,num1,flag&&(i==maxNum),false,roundNum);
				num0--;
			} 	
		}else{
    
    
			num1++;
			ret+=dfs(t,pos-1,num0,num1,flag&&(i==maxNum),false,roundNum);
			num1--;
		}
	}
	if(!flag){
    
    
		dp[pos][num0][num1]=ret;
	} 
	return ret;
}
void initDP(int m){
    
    
	map<int,int> m1;
	for(int num1=0;num1<=m;num1++){
    
    
		m1.emplace(num1,-1);		
	}
	map<int,map<int,int>> m2;
	for(int num0=0;num0<=m;num0++){
    
    
			m2.emplace(num0,m1);
	}
	//初始化dp 
	for(int pos=0;pos<m;pos++){
    
    
	 	dp.emplace(pos,m2);	
	}
}
int main(){
    
    
	cin>>l>>r;
	//dfs(1)表示[1,r],dfs(0)表示[1,l-1]
	init(l-1,a);
	init(r,b);
	initDP(b.size());
	int rRes= dfs(1,b.size()-1,0,0,true,true,b);
	initDP(a.size());
	int lRes= dfs(0,a.size()-1,0,0,true,true,a);
	//状态初始化 
	cout<<rRes-lRes<<endl;
	return 0;
} 

Guess you like

Origin blog.csdn.net/qq_33880925/article/details/129271855