题目链接:HDOJ3709

题意:给定区间【A,B】,求区间内的平衡数。定义是:选取某一个数字作为支点,各个数字到该数字的距离为力矩,使得杠杆平衡。如3218这个数,以1为支点时,3距离为2,2距离为1,左边之和为8,后边之和也为8,为平衡数


数位DP思想也很简单:既然不知道支点是那个点,枚举一发。既然不知道是否平衡,那么每个都来算

所以定义:dp【pos】【x】【st】:pos指当前枚举的数位,x指的是支点在哪,st指当前枚举的数位计算得到的和

要注意到st不能为负数(不然数组处理起来有问题),要特判


另外,这个题是做到的第一个前导0有影响的题

如果数为0,是可以的(既符合题意,又确实存在这个数)

如果数为00,是不可以的(符合题意,是平衡数,但是这个数跟0不是一个吗)

所以这个数有几位,数位最大是len,就会多统计了len-1个,在计算的时候要除掉


剩下的都是套路:

__int64 dp[30][30][2050];
int digit[30];

int t;
__int64 m,n;

__int64 dfs(int pos,int x,int st,bool flag){
	if (pos==0) return st==0;
	if (st<0) return 0;
	if (flag&&dp[pos][x][st]!=-1) return dp[pos][x][st];
	int num=flag?9:digit[pos];
	__int64 ans=0;
	for(int i=0;i<=num;i++){
		int tmp=st+i*(pos-x);
		ans+=dfs(pos-1,x,tmp,flag||i<num);
	}
	if (flag) dp[pos][x][st]=ans;
	return ans;
}

__int64 calc(__int64 x){
	if (x<0) return 0;
	int len=0;
	__int64 ans=0;
	while(x){
		digit[++len]=x%10;
		x/=10;
	}
	for(int i=1;i<=len;i++)
		ans+=dfs(len,i,0,0);
	return ans-len+1;
	//return ans;
}

int main(){
	//input;
	memset(dp,-1,sizeof(dp));
	scanf("%d",&t);
	while(t--){
		scanf("%I64d%I64d",&m,&n);
		printf("%I64d\n",calc(n)-calc(m-1));
	}
	return 0;
}