首页 > 其他 > 详细

Balanced Number HDU - 3709

时间:2021-05-30 00:23:39      阅读:18      评论:0      收藏:0      [点我收藏+]

原题链接
考察:数位dp
这个用循环没想出来怎么写,反倒是dfs写法很容易理解(.),菜是原罪,如果有循环预处理写法请告诉本蒟蒻QAQ.
思路:
??参考数位dp记搜模板.dfs带四个变量:

LL dfs(int pos,int sum,int mid,bool limit)
/*分别是枚举到第几位,平衡点的和(以平衡点在左为正),平衡点位置,是否是边界*/

??显然平衡点位置和目前枚举的和都是需要记录的,pos和Limit都是模板不用说.
??一个小剪枝是sum<0即可返回.
??最重要的,limit==0时才能记录.否则以左分支(无限制),右分支就会返回相同的结果.
大概需要找个时间补补前导零的做法(.

Code

#include <iostream> 
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 21,M = 2010;
int a[N],cnt;
LL f[N][M][N];//对应预处理,实际上省了共i位数这一维. 
LL dfs(int pos,int sum,int mid,bool limit)
{
	if(!pos) return !sum;
	if(sum<0) return 0;
	//为什么需要判断limit,因为有限制的前提下,相同状态计数结果不同 
	if(!limit&&f[pos][sum][mid]!=-1) return f[pos][sum][mid];
	int len = limit?a[pos]:9;
	LL res = 0;
	for(int i=0;i<=len;i++)
	  res+=dfs(pos-1,sum+(pos-mid)*i,mid,limit&&(i==len));
	if(!limit) f[pos][sum][mid] = res;
	return res;
}
LL dp(LL n)
{
	if(!n) return 1;
	cnt = 0;
	while(n) a[++cnt] = n%10,n/=10;
	/*枚举平衡点*/
	LL res = 0;
	for(int i=1;i<=cnt;i++)
	  res+=dfs(cnt,0,i,1);
	return res-cnt+1;
}
int main()
{
	int T;
	scanf("%d",&T);
	memset(f,-1,sizeof f);
	while(T--) 
	{
		LL l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",dp(r)-dp(l-1));
	}
	return 0;
}

Balanced Number HDU - 3709

原文:https://www.cnblogs.com/newblg/p/14826342.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!