数位DP-HDU-3709-Balanced Number

Balanced Number

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 3143 Accepted Submission(s): 1439

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 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].

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

Author
GAO, Yuan

Source
2010 Asia Chengdu Regional Contest

题意:给一个区间[x,y],求这个区间内balanced number的数量,对于balanced number的定义如下:
如果一个非负整数,能够在它所有的数位中找到一位作为支点,达成力矩平衡,那么就称这个数为balanced number。
例如,一个数4139,若以3作为支点,左边的力矩是4x2+1x1,右边是9x1,左右力矩等值反向,那么此数平衡,是一个balanced number。

同样是满足区间减法的,那么我们只需要找对于一个数值n,0到n有多少个balanced number(后简称bn),然后利用区间减法求出[x,y]中的bn数量。
用dp[size][pos][moment]存储size位数,支点在pos位,力矩为moment的数的个数。
那么利用记忆化搜索,我们对于一个数n,求出支点从第1位到第n位的bn个数便可得出结果。
在这里我们dfs求出[0,n]内的bn数量,具体方法是固定支点pos,以0~9(有封顶时不一定是9)作为最高位,递归找size-1位时bn数量,返回size位的bn数量。
dfs(int size,int pos,int moment,bool flag)中,size,pos,moment和dp数组的定义相同,而flag是表明当前求此位结果的过程中,有没有上限值封顶,比如在求4321的43xx时,得依次有2和1来封顶,不然可能就求到4399小游戏去了。
同时我们应该知道,若以支点左边(即大数位一边)的力矩方向作为正方向,在支点位置pos一定时,越是往小数位深度搜索,力矩和应该越小,那么一旦moment小于0了,应该及时返回,剪枝减少不必要的操作。
如果找到size小于0了,那么要看moment此时是否为0,是的话返回1,不是的话返回0。
递归求出[0,n]内的bn数量后,我们还应该减去n的长度再加一,原因是像0,00,000这样的重复考虑,我们应该删去其中多余的。

//
// main.cpp
// 数位DP-F-Balanced Number
//
// Created by 袁子涵 on 15/11/7.
// Copyright © 2015年 袁子涵. All rights reserved.
//
// 31ms 20756KB


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>

using namespace std;
long long int dp[35][35][2000],x,y;
int num[35];

long long int dfs(int size,int pos,int moment,bool flag)
{
    if (size<0) {
        return moment==0;
    }
    if (moment<0) {
        return 0;
    }
    if (!flag && dp[size][pos][moment]!=-1) {
        return dp[size][pos][moment];
    }
    long long int ans=0;
    int maxs=flag?num[size]:9;
    for (int i=0; i<=maxs; i++) {
        ans+=dfs(size-1, pos, moment+i*(size-pos), flag && i==maxs);
    }
    if (!flag) {
        dp[size][pos][moment]=ans;
    }
    return ans;
}

long long int handle(long long int t)
{
    memset(num, 0, sizeof(num));
    int size=0;
    long long int ans=0;
    while (t) {
        num[size++]=t%10;
        t/=10;
    }
    for (int i=0; i<size; i++) {
        ans+=dfs(size,i,0,1);
    }
    ans-=(size-1);
    return ans;
}


int main(int argc, const char * argv[]) {
    int T;
    cin >> T;
    memset(dp, -1, sizeof(dp));
    while (T--) {
        cin >> x >> y;
        long long int out;
        out=handle(y)-handle(x-1);
        cout <<  out << endl;
    }
    return 0;
}

你可能感兴趣的:(c,dp)