HDU-3709-Balanced Number(数位DP)

Balanced Number

Problem Description

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 42 + 11 = 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].

Input

The 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 ≤ 1018).

Output

For 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

解题思路:

数位DP。
解题关键在于枚举轴点,以及距离的计算。
依次枚举每一个点作为轴点。最后所有的距离有正有负。如果正好等于0说明就是一个平衡数。如果在搜索过程中 sta < 0可以提前返回0,因为sta是先递增后递减的。如果某一时刻小于0,那么他不可能再回升了。
思考:
为什么枚举不同点为轴点的时候,不会出现被重复计算的数字。
最开始写的时候想到的就是这样的解法。想到这个问题没想通。觉得会有重复计算的而不会去重,就放弃了正解。纠结了两个小时之后去搜题解,发现题解就是和我写的一样的。稍加思考可以发现,每个数确实只有一个满足条件的轴。
需要去重的只有0,因为0不论哪个位置都会被重复计算。
证明:
不妨任意假设一个数a1a2a3a4 是平衡数 且平衡轴为a2,那么意味着a1 = a3+2*a4,这时如果平衡轴往右边移动,即假设a3也是平衡轴,那么等式左边必然增大,而等式右边必然减小。显然等式两边不相等。
得证:一个数至多只有一个平衡轴。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
using namespace std;
int a[20];
int dp[20][3000][20];

int dfs(int pos,int scl,int sta,int limit)
{
    if(pos == -1) return sta == 0 ? 1 : 0;
    if(sta < 0) return 0;
    if(!limit && dp[pos][sta][scl] != -1) return dp[pos][sta][scl];
    int up = limit ? a[pos] : 9;
    int tmp = 0;
    for(int i = 0 ; i <= up ; i ++)
        tmp += dfs(pos-1,scl,sta+i*(pos-scl),limit && a[pos] == i);
    if(!limit) dp[pos][sta][scl] = tmp;
    return tmp;
}

int solve(int x)
{
    int pos = 0;
    while(x)
    {
        a[pos++] = x%10;
        x /= 10;
    }
    int res = 0;
    for(int i = 0 ; i < pos ; i ++)
        res += dfs(pos-1,i,0,1);
    return res-pos+1; // 0加了pos次,所以要减去pos-1次
}

signed main()
{
    int n,a,b;
    cin>>n;
    while(n--)
    {
    memset(dp,-1,sizeof(dp));
        cin>>a>>b;
        cout<<solve(b) - solve(a-1)<<endl;
    }
    return 0;
}

发布了104 篇原创文章 · 获赞 7 · 访问量 4085

猜你喜欢

转载自blog.csdn.net/qq_43461168/article/details/103328318