(HDU - 3709)Balanced Number(数位DP)

Topic link: Problem - 3709

Question: Given an interval [a, b], find the number of equilibrium numbers in the interval. The so-called balance number means that there is one digit as the balance point, and the moments of the left and right numbers are equal.

Analysis, we can directly enumerate the balance points in this question , and then find the sum of the balance numbers corresponding to each balance point, and finally get the answer.

It should be noted that the prefix 0 is the case. For the answer of 000000000, we should not actually count the answer, that is to say, we need to consider the leading 0 in the process of digitizing the DP, and also when pos=0 is returned at the end. Determine whether there is a leading 0 at present. If there is a leading 0, return 0 directly, otherwise return the bool value of the moment difference between the left and right of the current balance number and 0. One thing to note here is that we do not consider the leading 0 in the digital DP, but this will cause us to consider one less number, which is 0, so if l~r contains 0, we should also add a 1, corresponding to In the code, if x<0, return -1 directly in the solve function.

Of course, we can also ignore the leading 0 in the digital DP process, and subtract the contribution of the leading 0 at the end, that is, ans-pos+1

The code for the two methods is attached below:

Leading 0s are considered in the digital DP process:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=33;
ll f[N][N][5203];//f[i][j][k]表示当前遍历到第i位,支点为第j位,左边比右边多k的平衡数 
int a[N];
ll dfs(int pos,int pivot,int sub,int lead,int limit)
{
	if(sub<0) return 0;//sub是先变大后变小,由于一开始是0,所以当sub小于0时说明之后sub也是变小所以不符合题意,直接剪枝 
	if(pos==0)
	{
		if(!lead)
			return sub==0;
		else 
			return 0;
	}
	if(!lead&&!limit&&f[pos][pivot][sub]!=-1) return f[pos][pivot][sub];
	int up=limit?a[pos]:9;
	ll ans=0;
	for(int i=0;i<=up;i++)
		ans+=dfs(pos-1,pivot,sub+(pos-pivot)*i,lead&&(i==0),limit&&(i==up));
	if(!lead&&!limit) f[pos][pivot][sub]=ans;
	return ans;
}
ll solve(ll x)
{
	if(x<0) return -1;
	ll ans=0,pos=0;
	while(x)
	{
		a[++pos]=x%10;
		x/=10;
	}
	for(int pivot=1;pivot<=pos;pivot++)
		ans+=dfs(pos,pivot,0,1,1);
	return ans;
}
int main()
{
	int T;
	cin>>T;
	ll l,r;
	memset(f,-1,sizeof f);
	while(T--)
	{
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
	}
	return 0;
}

Leading 0s are not considered in the digital DP process:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
int a[23];
ll dp[20][20][5200];
ll dfs(int pos,int o,int f,int flag)
{
	if(pos==0) return f==0;
	if(dp[pos][o][f]!=-1&&flag) return dp[pos][o][f];
	ll ans=0;
	int x=flag?9:a[pos];
	for(int i=0;i<=x;i++) ans+=dfs(pos-1,o,f+(pos-o)*i,flag||i<x);
	if(flag) dp[pos][o][f]=ans;
	return ans;
}
ll solve(ll x)
{
	int pos=0;
	while(x)
	{
		a[++pos]=x%10;
		x/=10;
	}
	ll ans=0;
	for(int i=1;i<=pos;i++)
		ans+=dfs(pos,i,0,0);
	return ans-pos+1;
}
int main()
{
	int T;
	cin>>T;
	ll l,r;
	memset(dp,-1,sizeof dp);
	while(T--)
	{
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/AC__dream/article/details/123964432