Balanced Number(数位DP)
D - Balanced Number
A balanced number is a non-negative integer that can be balanced if a pivot is placed at some digit. More specifically, imagine each digit as a box with weight indicated by the digit. When a pivot is placed at some digit of the number, the distance from a digit to the pivot is the offset between it and the pivot. Then the torques of left part and right part can be calculated. It is balanced if they are the same. A balanced number must be balanced with the pivot at some of its digits. For example, 4139 is a balanced number with pivot fixed at 3. The torqueses are 4*2 + 1*1 = 9 and 9*1 = 9, for left part and right part, respectively. It's your job
to calculate the number of balanced numbers in a given range [x, y].
to calculate the number of balanced numbers in a given range [x, y].
InputThe input contains multiple test cases. The first line is the total number of cases T (0 < T ≤ 30). For each case, there are two integers separated by a space in a line, x and y. (0 ≤ x ≤ y ≤ 10 18).OutputFor each case, print the number of balanced numbers in the range [x, y] in a line.Sample Input
2
0 9
7604 24324
Sample Output
10 897
题意:找出区间内平衡数的个数,所谓平衡数,就是以这个数字的某一位为支点,左右两边的数字乘力矩之和相等。
题解:比如4139
digit 4 1 3 9
len 4 3 2 1 对于每一位来说比如第四位4 for循环遍历这一位的数字就是0~4 对于第三位1来说就是遍历0~1。for循环遍历每一位作为支点,然后对于dfs中从最高位到最低位搜一遍,对于4139这个数来说,假设支点在2位置,len从4~1,sum=4*2+1*1+3*0+9*(-1)=0 所以4139是一个平衡数,sum=0,返回1。遍历完所有支点位置以及每一位从0到up,得到的和就是ans值。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 typedef long long ll;
7 ll dp[20][20][2000];
8 int digit[110];
9 //dfs中4个参数,len代表当前所在的位数,zhou代表支点位置
10 //sum代表支点左边的数乘上力矩的加和-右边的数乘上力矩的加和
11 //当sum为0时 代表以zhou这个位置为支点的存在一个数是平衡数。
12 //limit代表的是每一位的上限
13 ll dfs(int len,int zhou,int sum,bool limit)
14 {
15 if(!len)
16 return sum?0:1;
17 if(!limit&&dp[len][zhou][sum]!=-1)
18 return dp[len][zhou][sum];
19 if(sum<0)
20 return 0;
21 int up=limit?digit[len]:9;
22 ll ans=0;
23 for(int i=0;i<=up;i++)
24 {
25 ans+=dfs(len-1,zhou,sum+i*(len-zhou),limit&&i==up);// sum+i*(len-zhou)表示当前的某一位上的某个数和它到支点距离的乘积
26 }
27 if(!limit)
28 dp[len][zhou][sum]=ans;
29 return ans;
30 }
31 ll solve(ll x)
32 {
33 if(x<0)
34 return 0;
35 ll len=0;
36 while(x)
37 {
38 digit[++len]=x%10;
39 x/=10;
40 }
41 ll ans=0;
42 for(int i=len;i>0;i--)
43 {
44 ans+=dfs(len,i,0,true);
45 }
46 return ans-len+1;//因为0 00 000只能算一个
47 }
48 int main()
49 {
50 int casen;
51 cin>>casen;
52 memset(dp,-1,sizeof(dp));
53 while(casen--)
54 {
55 ll l,r;
56 scanf("%lld%lld",&l,&r);
57 printf("%lld\n",solve(r)-solve(l-1));
58 }
59 return 0;
60 }