HDU 3709 Balanced Number 求区间内的满足是否平衡的数量 (数位dp)
平衡数的定义是指,以某位作为支点,此位的左面(数字 * 距离)之和 与右边相等,距离是指某位到支点的距离;
题意:求区间内满足平衡数的数量 ;
分析:很好这又是常见的数位dp , 不过不同的是我们这次需要枚举是哪个位置是平衡点 , 一开始我是想说搜索到最后以为 ,然后得到这个数的位数 ,在判断平衡位置 , 想到这样的话 , 这就说明了我对数位dp 还是不太熟悉的 ,因为这样的话dfs() 里面的sum , emmm是找不到状态的 ;
正解: 依然是枚举平衡点的位置 ,这个思路没有问题 , 但是这个却是在so(_) 函数里面枚举 ,啊这样就妙不可言了, 这样的话只要我们在dfs()里面增加变量 k ,表示是平衡点的位置 , 那这样的话我的sum 就是记录 从左到右的贡献 , 因为是从左到右的枚举 , 左边加, 右边减 , 所以是不是sum<0 , 就肯定是不行的嘛 ;哦!还有一个重点 ,因为0也是平衡数来的 , 所以我们这样的枚举平衡点就加了ans-1 次0 的贡献 ,这里巨坑一开始没有想到,其他代码打出来了 , 答案不对 ,然后找程序的错误 ,其实这里是关键来的
#include<stdio.h> #include<string.h> #include<cmath> using namespace std ; #define ll long long ll dp[20][20][2002]; ll a[20]; ll dfs(int pos , int k , int sum , bool limit) { if(pos==-1) return sum==0; if(sum<0) return 0; if(!limit && dp[pos][k][sum]!=-1) return dp[pos][k][sum]; int up=limit?a[pos]:9; ll ans=0; for(int i=0 ; i<=up ; i++) { ans+=dfs(pos-1,k,sum+(pos-k)*i,limit&&i==a[pos]); } if(!limit) dp[pos][k][sum]=ans; return ans; } ll so(ll x) { int ans=0; ll sum=0; while(x) { a[ans++]=x%10; x/=10; } for(ll i=0 ; i<ans ; i++) sum+=dfs(ans-1,i,0,1); return sum-(ans-1); } int main( ) { int t; memset(dp,-1,sizeof(dp)); scanf("%d",&t); while(t--) { ll l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",so(r)-so(l-1)); } }