[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\n",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\n",solve(r)-solve(l-1)); } return 0; }