HDU3709 Balanced Number 数位DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709


题目大意:定义平衡数:以一个数的某一位为支点,其左右各个位分别乘以力矩的和是相等的。比如4139这个数,我们以3为力矩,左边的力矩和为4*2+1*1=右边的力矩和9*1。下载给出一个区间[l,r](0<=l<=r<=10^18),找出区间内有多少个平衡数。


分析:数位DP。我们用dp(i,j,k)来表示以第j位为支点的力矩和为k时的i位数有多少个,这样我们在枚举支点的过程中分别深搜。


实现代码如下:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[25][25][2005];
int dig[25],len;
ll dfs(int pos,int o,int l,int lim) //o为支点,l为力矩
{
    if(pos<0) return l==0;
    if(l<0) return 0; //力矩和为负,说明支点选靠前了,没必要继续考虑了
    if(!lim&&dp[pos][o][l]!=-1) return dp[pos][o][l];
    int num=lim?dig[pos]:9;
    ll ans=0;
    for(int i=0;i<=num;i++)
    {
        int nex=l;
        nex+=(pos-o)*i;
        ans+=dfs(pos-1,o,nex,lim&&(i==num));
    }
    if(!lim) dp[pos][o][l]=ans;
    return ans;
}
ll count(ll x)
{
    len=0;
    while(x)
    {
        dig[len++]=x%10;
        x/=10;
    }
    memset(dp,-1,sizeof(dp));
    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;
    ll l,r;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d",&l,&r);
        printf("%I64d\n",count(r)-count(l-1));
    }
    return 0;
}


你可能感兴趣的:(HDU3709 Balanced Number 数位DP)