题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709
题目大意:选取某一个数字作为支点,各个数字到该数字的距离为力矩,使得杠杆平衡。如3218这个数,以1为支点时,3距离为2,2距离为1,左边之和为8,后边之和也为8,为平衡数,求在[x,y]范围内平衡数的数量。
只要枚举每个支点的位置,其他的是个裸数位dp,感觉自己又理解了一点,哈哈哈
另外,这个题是做到的第一个前导0有影响的题
如果数为0,是可以的(既符合题意,又确实存在这个数)
如果数为00,是不可以的(符合题意,是平衡数,但是这个数跟0不是一个吗)
所以这个数有几位,数位最大是len,就会多统计了len-1个,在计算的时候要除掉
AC代码:
import java.util.Scanner;
public class Main {
static int a[]=new int[20];
static long dp[][][]=new long[20][20][2050];
static long solve(long x){
int pos=0;
long ans=0;
while(x!=0){
a[++pos]=(int) (x%10);
x/=10;
}
for(int i=1;i<=pos;i++){
ans+=dfs(pos,i,0,true);
}
return ans-pos+1;
}
//pos为当前枚举的数位,x为平衡点的位置,st为左边点到平和点的力矩和,limit代表是否枚举到了上限
static long dfs(int pos,int x,int st,boolean limit){
if(pos==0)
return st==0?1:0;
if(st<0)
return 0;
if(!limit&&dp[pos][x][st]!=-1)
return dp[pos][x][st];
int num=(limit?a[pos]:9);
long ans=0;
for(int i=0;i<=num;i++){
int tmp=st+i*(pos-x);
ans+=dfs(pos-1,x,tmp,limit&&i==a[pos]);//保存左边点到平和点的力矩和为tmp的状态数量
}
if(!limit)
dp[pos][x][st]=ans;
return ans;
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
for(int i=0;i<dp.length;i++){
for(int j=0;j<dp[i].length;j++){
for(int k=0;k<dp[i][j].length;k++){
dp[i][j][k]=-1;
}
}
}
int t=sc.nextInt();
while(t-->0){
long x=sc.nextLong();
long y=sc.nextLong();
System.out.println(solve(y)-solve(x-1));
}
sc.close();
}
}