hdoj3709(数位dp)

题目链接:https://vjudge.net/problem/HDU-3709

题意:求出[l,r]中的平衡数,平衡数即存在一个中心点使得两边的力矩和相等。

思路:首先需要知道一个数最多只有一个中心点,可以通过反证法轻松得出,所以我们可以对长为pos的数枚举其中心点。用dp[pos][m][sum]表示长为pos+1、中心点在第m位、现在的力矩和为sum的数的个数。中心点一边的力矩和最大大约为1500,所以离散化一下,用1500表示0。另外要注意的是每次枚举中心点都会将0算入,所以最后要减取多加的pos-1个0。

AC代码:

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;

const int key=1500;
int T;
LL a[20],dp[20][20][2*key];

LL dfs(int pos,int m,int sum,bool limit){
    if(pos==-1) return sum==key;
    if(!limit&&dp[pos][m][sum]!=-1) return dp[pos][m][sum];
    int up=limit?a[pos]:9;
    LL tmp=0;
    for(int i=0;i<=up;++i)
        tmp+=dfs(pos-1,m,sum+i*(pos-m),limit&&i==a[pos]);
    if(!limit) dp[pos][m][sum]=tmp;
    return tmp;
}

LL solve(LL x){
    int pos=0;
    LL ans=0;
    while(x){
        a[pos++]=x%10;
        x/=10;
    }
    for(int i=0;i<pos;++i)
        ans+=dfs(pos-1,i,key,true);
    return ans-pos+1;
}

int main(){
    memset(dp,-1,sizeof(dp));
    scanf("%d",&T);
    while(T--){
        LL l,r;
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",solve(r)-solve(l-1));
    }
    return 0;
}

 

posted @ 2019-04-24 21:42  Frank__Chen  阅读(108)  评论(0编辑  收藏  举报