HDU 3709 Balanced Number(数位dp)

来源:互联网 发布:pid算法 编辑:程序博客网 时间:2024/05/19 18:37

Balanced Number

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


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

20 97604 24324

Sample Output

10897

Author

GAO, Yuan

Source

2010 Asia Chengdu Regional Contest



        人生第一道数位dp,还几乎是自己想出来的,纪念一下……

        数字要平衡,即力矩平衡。一般来说,数位dp求一个区间内满足条件的方案数,都是要用区间的性质,即对于询问区间[l,r]我们的最后过往往是拿0~r的个数减去0~l-1的个数。然后dp的时候,就按照数位来做。这道题因为有力矩的存在,所以也与支点的选取有关,所以我们要加一维表示支点。dp[i][j][k]表示,当前长度为i支点为j力矩和为k的方案数。那么很容易得出状态转移方程:dp[i][j][k]=sigma(dp[i-1][j][k-x*(i-j)],其中sigma是关于x的求和,x即为最后一位的数字。这个转移方程也很容易理解,但是如何处理一个大小关系呢?

        这里,我们想到用记忆化搜索的方式解决,在原本的三个参数的基础上,加一个lim,即搜索到当前位置的时候是否有数字大小的限制。注意到,如果当前位有限制,而且该位最大不能超过n,那么x的枚举就是0~n,当x小于n的时候,搜索下一位的时候就不需要有限制了,而当x等于n的时候还将要有限制,最后,在返回的时候,如果没有限制就把对应参数的dp值记录到数组中。具体见代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<cstring>#include<cstdlib>#include<iomanip>#define N 2100#define LL long longusing namespace std;LL dp[20][20][2100];int num[20],n;LL dfs(int len,int pos,int p,bool lim)//lim表示是否有限制{    if (!len) return !p;    if (p<0) return 0;    if (!lim&&dp[len][pos][p]!=-1) return dp[len][pos][p];//如果没有限制而且已经计算过则直接返回    LL up=9,res=0;    if (lim) up=num[len];    for(int i=0;i<=up;i++)        res+=dfs(len-1,pos,p+i*(len-pos),lim&&i==up);//如果没到上限则下一位开始不用限制    if (!lim) dp[len][pos][p]=res;//没限制则储存dp值    return res;}LL sum(LL x){    if (x<0) return 0;    LL res=0,tot=0;    while(x>0)    {        num[++tot]=x%10;        x/=10;    }    for(int i=1;i<=tot;i++)        res+=dfs(tot,i,0,1);//结果还要对支点求和    return res-(tot-1LL);//减去多个0的重复情况}int main(){    int T_T;    cin>>T_T;    memset(dp,-1,sizeof(dp));    while(T_T--)    {        LL l,r;        scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",sum(r)-sum(l-1));    }    return 0;}

原创粉丝点击