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

题目链接:Problem - 3709

题意:给定区间[a,b],求区间内平衡数的个数。所谓平衡数即有一位做平衡点,左右两边数字的力矩相等。

分析,这道题我们直接对平衡点进行枚举即可,然后分别求出来每个平衡点对应的平衡数求和,最后即为答案。

需要注意的是前缀0的情况,对于000000000这样的答案我们实际上是不应该计入答案的,也就是说我们在数位DP的过程中需要考虑前导0,在pos=0最后返回的时候也要判断当前是否有前导0的存在,如果有前导0就直接返回0,否则返回当前平衡数左边和右边的力矩差与0判等的bool值。这里需要注意的一点是由于我们在数位DP中没有考虑前导0,但这会导致我们少考虑一个数,那就是0,所以如果l~r内包含0,我们还应该加上一个1,对应到代码中就是若x<0,则在solve函数中直接返回-1。

当然我们也可以在数位DP过程中不考虑前导0,而在最后统一减去前导0的贡献,也就是ans-pos+1

下面分别附上两种方法的代码:

数位DP过程中考虑前导0:

#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;
}

数位DP过程中不考虑前导0:

#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;
}

猜你喜欢

转载自blog.csdn.net/AC__dream/article/details/123964432