Balanced Number HDU - 3709(数位 dp )

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 ≤ 10 18).
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,枚举支点位置。dp[u][pivot][torque]代表长度为u,重心在pivot,力矩为torque的数字个数。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int digit[20];
LL dp[20][20][2010];    //dp[u][pivot][torque]代表长度为u,重心在pivot,力矩为torque的数字个数

LL Dfs(int len, int pivot, int torque, bool limit)
{
    if(len == 0)    return torque == 0;	//如果遍历完了,那么看两遍力矩是否相等,如果两边之差等于0,那么说明是平衡数
    if(torque < 0)  return 0;	//力矩没有负数,如果有,那么不符合情况,返回0
    //如果,高位还没有遍历完,即遍历低位时没有限制,并且dp已经遍历过了,直接返回
    if(limit == false && dp[len][pivot][torque] != -1)  return dp[len][pivot][torque];
    LL ans = 0;
    //如果有限制,那么最多就能遍历到该位最大值,否则就一直遍历到9
    int num = limit ? digit[len] : 9;
    for(int Digit = 0; Digit <= num; Digit++)
        ans += Dfs(len - 1, pivot, torque + Digit * (len - pivot), limit && Digit == num);
    //没有限制时才可以进行记忆化
    if(limit == false)  dp[len][pivot][torque] = ans;
    return ans;
}

LL Solve(LL n)
{
    int len = 0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    LL ans = 0;
    //枚举支点的位置
    for(int pivot = 1; pivot <= len; pivot++)
        ans += Dfs(len, pivot, 0, true);
    //因为我们在遍历的时候,不管支点在什么地方,每一个dfs都会遍历到0,
    //这样就出现了有前导0的情况,所以要删去len-1中0的情况
    return ans - len + 1;
}

int main()
{
    int Case;
    cin >> Case;
    memset(dp, -1, sizeof(dp));
    while(Case--)
    {
        LL n, m;
        scanf("%lld%lld", &n, &m);
        printf("%lld\n", Solve(m) - Solve(n - 1));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值