Hdu 3709 Balanced Number

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

记忆化 ,用的数位dp的模式感觉 ,数位dp也是菜开始学的 感觉很难看了一些博客 最终艰难的把它a了,写个题解来巩固一下把尽量写得详细点。

网上很多博客都说直接枚举支点 其实对这个不是很熟,下面就用我的话来表述一下这个题吧。

首先是暴力dfs,对于指定长度的一个数,小于它的数有多少是平横数,根据自己理解到的数位dp的东西,根据指定长度,那么对于长度达不到的数前面补0,这样就避免了位数的关系 而且这样也可以保证每一位数都能枚举到,那么这个题 我们枚举那个数位是平衡点 假设是第i位是平衡点 那么只需要重左加到右每次加的时候乘上位置差就可以了。

然后对于dp记忆 dp[i][j][sum]  表示剩余长度为i的时候 平衡点为就的时候 两边边差为sum的时候有多少种平衡情况 注意havemax标记 因为如果前一位不是最大值得时候那么当前这一为可以随便取0~9 否则就只能取到当前位的最大值。注意dp记录的也只能是没有最大值得情况 因为能对于每一种情况 如果没有最大值 那么枚举的后续都是一样的。ok上代码

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;
#define LL long long
LL dp[20][20][2050];
int dig[20];
LL dfs(int len,int pos,int sum,bool haveMax)
{
	if(len<0)
	return sum==0?1:0;
	if(!haveMax && dp[len][pos][sum]!=-1)
	return dp[len][pos][sum];
	int maxNum = haveMax?dig[len]:9;
	LL ans = 0;
	for(int i = 0;i<=maxNum;i++)
	{
		ans+=dfs(len-1,pos,sum+(len-pos)*i,haveMax&&i==maxNum);
	}
	if(!haveMax)
	{
		dp[len][pos][sum] = ans;
	}
	return ans;
}
LL solve(LL n)
{
	int len = 0;
	while(n)
	{
		dig[len++] = n%10;
		n/=10;
	}
	LL ans = 0;
	for(int i = 0;i<len;i++)
	{
		ans+=dfs(len-1,i,0,true);
		//printf("%lld\n",ans);
	}
	return ans-(len-1);
}
int main()
{
	int t;
	memset(dp,-1,sizeof(dp));
	cin >> t;
	while(t--)
	{
		LL l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值