题目链接: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;
}