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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值