Simple digit dp and understanding of leading 0

Posted by nita on Sat, 26 Feb 2022 05:02:51 +0100

Essence of digital dp:

  • A fast enumeration method, which satisfies the nature of dp, and then carries out memory search.

Example: Niuke - Digital children

Title Description:

Jiufeng has been addicted to digital dp recently. On this day, he created another digital dp problem:
Give an interval [l,r][l,r][l,r], find out how many numbers in this interval meet the following conditions:
1. The sum of every two adjacent digits is prime.   

2. At least one digit is 1.

3. No leading 0.

Please write a program to help him solve the problem.

Enter Description:

One line of two integers L, R (1 < = l < = R)<= ), indicating that the given interval is [l,r].

Output Description:

One integer per line indicates the number of conditions in the interval.

Idea:

General idea: we calculate the number of conditions satisfied in the middle of 1 ~ r minus the number of conditions satisfied in 1 ~ l - 1.

  1. First, we preprocess and process the number of all the qualified numbers with the i-th bit and the highest j.
  2. Then enumerate each bit of l or r from the highest bit to the lowest bit (assuming that x is the number to be enumerated for each bit). Remember that because it cannot contain leading zeros, the highest bit should be enumerated from 1 to x - 1, and the other bits are from 0 to x - 1.
  3. Finally, we have to judge whether there are two adjacent numbers in the digits of L or r each time. The addition is not a prime number. If there is one, we will directly jump out of the loop after enumerating that bit, because the number after enumerating will not satisfy the addition of any two adjacent numbers into a prime number. If you come to the end, remember + 1, because l or R is also satisfied.

Leading zero problem:

  1. Whether the leading 0 needs special treatment depends on whether the existence of the leading 0 will affect the nature of the problem.
  2. This problem will affect. For example, if you regard 0012 and 12 as the same, it will affect, because 0 + 0 = = 0 in 0012 is not a prime number, so it does not match, while 1 + 2 = = 3 in 12 matches.
  3. stay AcWing - 1082. Digital game Because 0012 and 12 are not reduced, 0 will not affect the following.

AC Code:

#include<iostream>
#include<set>
#include<vector>
using namespace std;

# define int long long 

const int N = 15;

set<int>se;
int a[8] = {2,3,5,7,11,13,17,19};
int f[N][N][2];

void init()
{
	for(int i = 0;i < 8;i ++) se.insert(a[i]);
	for(int i = 0;i <= 9;i ++) f[1][i][i == 1] = 1;
	
	for(int i = 2;i < 15;i ++)
	{
		for(int j = 0;j < 10;j ++)
		{
			for(int k = 0;k < 10;k ++)
			{
				if(se.count(j + k))
				{
					if(j == 1)
					    f[i][j][1] += f[i - 1][k][0] + f[i - 1][k][1];
				    else
				    {
				    	f[i][j][1] += f[i - 1][k][1];
				    	
				    	f[i][j][0] += f[i - 1][k][0];
					}
				}
			}
		}
	}
}

int dp(int n)
{
	if(!n) return 0;
	
	vector<int>ve;
	
	while(n)
	{
		ve.push_back(n % 10);
		n /= 10;
	}
	
	int res = 0, last = -100, flag = 0;
	n = ve.size() - 1;
	for(int i = ve.size() - 1;i >= 0;i --)
	{
		int x = ve[i];
		for(int j = i == n;j < x;j ++)
		{
			if(!se.count(last + j) && last > 0) continue;
			if(j == 1 || flag) 
			    res += (f[i + 1][j][0] + f[i + 1][j][1]);
			else 
				res += f[i + 1][j][1];
		}
	
		if(last != -100 && !se.count(last + x)) break;
		if(x == 1)flag = 1;
		last = x;
		
		if(!i  && flag) res ++;
	}
	
	for(int i = 1;i < ve.size();i ++)
	{
		for(int j = 1;j < 10;j ++)
		{
			res += f[i][j][1];
		}
	}
	return res;
}

signed main()
{
	init();
	int l,r;
	cin >> l >> r;
	cout << dp(r) - dp(l - 1) << endl;
	return 0;
}

Pretreatment:

I think this step is the hardest to think of

const int N = 15;

set<int>se;
int a[8] = {2,3,5,7,11,13,17,19};
int f[N][N][2];//The three brackets indicate the highest digit respectively, and whether the value represented by the highest digit contains 1

void init()
{
	for(int i = 0;i < 8;i ++) se.insert(a[i]);
	for(int i = 0;i <= 9;i ++) f[1][i][i == 1] = 1;
	
	for(int i = 2;i < 15;i ++)
	{
		for(int j = 0;j < 10;j ++)//j stands for standard
		{
			for(int k = 0;k < 10;k ++)//k represents the previous digit
			{
				if(se.count(j + k))//Judge whether two adjacent bits are bit prime numbers
				{
					if(j == 1)//When the highest bit is 1, it can be counted whether or not the preceding digits contain 1
					    f[i][j][1] += f[i - 1][k][0] + f[i - 1][k][1];
				    else
				    {
				    	//Here, it can only be divided into two parts including 1 and excluding 1 according to whether it contains 1 or not
				    	f[i][j][1] += f[i - 1][k][1];
				    	
				    	f[i][j][0] += f[i - 1][k][0];
					}
				}
			}
		}
	}
}

dp function:

int dp(int n)
{
	if(!n) return 0;
	
	vector<int>ve;
	
	while(n)
	{
		ve.push_back(n % 10);
		n /= 10;
	}
	
	int res = 0, last = -100;//last is used to record the previous bit. last == -100 is for the convenience of special judgment in the first cycle
	int flag = 0;//flag is for the convenience of judging whether the digit of n contains 1
	n = ve.size() - 1;
	for(int i = ve.size() - 1;i >= 0;i --)
	{
		int x = ve[i];
		for(int j = i == n;j < x;j ++)//i == n tips
		{
			if(!se.count(last + j) && last > 0) continue;
			if(j == 1 || flag) 
			    res += (f[i + 1][j][0] + f[i + 1][j][1]);
			else 
				res += f[i + 1][j][1];
		}
	
		if(last != -100 && !se.count(last + x)) break;
		if(x == 1)flag = 1;
		last = x;
		
		if(!i  && flag) res ++;
	}
	//Special handling leading 0
	for(int i = 1;i < ve.size();i ++)
	{
		for(int j = 1;j < 10;j ++)
		{
			res += f[i][j][1];
		}
	}
	return res;
}

Well, these are some of my recent experiences in learning digital dp. I hope I can share them with you.

Topics: C++ Algorithm Dynamic Programming