HDU 3709 Balanced Number (数位DP+思维)【模板】

来源:互联网 发布:windows无法连接到cmcc 编辑:程序博客网 时间:2024/05/16 18:29

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 ≤ 10 18).
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

 【题解】 

 这道题很经典,套路很深,为什么呢?因为题目是这样说的:判断一个数方法是以某一位为支点,左边的数乘以力矩的和等于右边的数乘以力矩的和,这句话很限制我们的思维(至少我是跳坑里了),所以我一直在考虑怎么同时表示左边的力矩和和右边的力矩和,试了好多写法都不对,后来看了下别人博客,发现更巧的方法,那就是支点选定以后,从左往右依次求力矩乘积的和:(当前位置-支点位置)*力矩,可以想象,支点左边单个的力矩乘积肯定是正的,所以支点左边一定是越加越大的,而到了支点右边,单个的力矩乘积一定是负的,所以这个值肯定是越来越小了,而我们只需要判断那个点使得力矩和为0就符合题意了,同时剪枝:如果力矩由正直接变负了,那再往后肯定也是负的,就不可能出现答案了,所以这时候直接剪掉,这会提高很多效率,最后还要注意要刨除0,00,000,0000这种情况,可以看到,这种情况的个数就是len-1个。

 每次遍历不同支点位置,结果累加就是答案。

 

【AC代码】

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;typedef __int64 ll;ll dp[30][30][5000];ll m,n;int num[30];ll dfs(int pos,int zhi,int ju,bool limit)//依次是 当前位置  支点位置  力矩大小  上限情况{    if(pos < 0) return ju == 0 ;//组合完了就退出    if(ju < 0) return 0; //力矩由正直接变负   剪枝退出    if(!limit && dp[pos][zhi][ju]!=-1) return dp[pos][zhi][ju];    ll ans=0;    int endi= limit ? num[pos]:9;//    for(int i=0;i<=endi;++i)    {        int next_ju=ju;        next_ju+=(pos-zhi)*i;//力矩乘积的和        ans+=dfs(pos-1,zhi,next_ju,limit && i==endi);    }    if(!limit) dp[pos][zhi][ju]=ans;    return ans;}ll solve(ll x){    int len=0;    while(x)    {        num[len++]=x%10;        x/=10;    }    ll ans=0;    for(int i=0;i<len;++i)//遍历不同支点位置时的答案    {        ans+=dfs(len-1,i,0,1);    }    return ans-(len-1);//出去0,00,000等的情况}int main(){    int t;    memset(dp,-1,sizeof(dp));    scanf("%d",&t);    while(t--)    {        scanf("%I64d %I64d",&m,&n);        printf("%I64d\n",solve(n)-solve(m-1));    }    return 0;}


原创粉丝点击