[hdu3709]Balanced Number(数位dp)

题意:在l-r之间寻找可以满足平衡数条件的个数。

解题关键:数位dp,由于非零数的支点有且只存在一个,故只有0存在重复,最后需要删去。

1001也只存在1种情况的,仔细想想。

转移方程:$dp[i][j] +  = dp[i - 1][j - a[i]*(o - i)]$

法一:390ms

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll dp[20][2000],l,r;
int t[20],o;
ll dfs(int pos,int sta,int limit){
    if(pos==-1) return sta==0;
    if(sta<0) return 0;
    if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
    ll up=limit?t[pos]:9,ans=0;
    for(int i=0;i<=up;i++)
        ans+=dfs(pos-1,sta+(pos-o)*i,limit&&i==up);
    if(!limit) dp[pos][sta]=ans;
    return ans;
}
ll solve(ll x){
    int pos=0;
    while(x){
        t[pos++]=x%10;
        x/=10;
    }
    ll ans=0;
    for(int i=0;i<pos;i++) memset(dp,-1,sizeof dp),o=i,ans+=dfs(pos-1,0,1);
    return ans-pos+1;
}
int main(){
    int T;scanf("%d",&T);
    memset(dp,-1,sizeof dp);
    while(T--){
        scanf("%lld%lld",&l,&r);
        printf("%lld
",solve(r)-solve(l-1));
    }
    return 0;
}

法二:将支点位置hash一下,31ms

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll dp[20][20][2000],l,r;
int t[20],o;
ll dfs(int pos,int sta,int limit){
    if(pos==-1) return sta==0;
    if(sta<0) return 0;
    if(!limit&&dp[pos][o][sta]!=-1) return dp[pos][o][sta];
    ll up=limit?t[pos]:9,ans=0;
    for(int i=0;i<=up;i++)
        ans+=dfs(pos-1,sta+(pos-o)*i,limit&&i==up);
    if(!limit) dp[pos][o][sta]=ans;
    return ans;
}
ll solve(ll x){
    int pos=0;
    while(x){
        t[pos++]=x%10;
        x/=10;
    }
    ll ans=0;
    for(int i=0;i<pos;i++) o=i,ans+=dfs(pos-1,0,1);
    return ans-pos+1;
}
int main(){
    int T;scanf("%d",&T);
    memset(dp,-1,sizeof dp);
    while(T--){
        scanf("%lld%lld",&l,&r);
        printf("%lld
",solve(r)-solve(l-1));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/elpsycongroo/p/7790245.html