HDU-3709 Balanced Number (数位dp)

来源:互联网 发布:网络整合营销4i原则 编辑:程序博客网 时间:2024/05/19 19:16

题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=3709。

题目大意:给定你一个区间 [x,y],要你求出这个区间里是平衡数的数的个数,平衡数的定义为:在一个数中取定一个平衡位置,满足该位置左边的数的重量等于右边的数的重量,重量的计算公式为该位的值乘上到选定位置的距离的差值,比如,4139,取定3为平衡位置,则左边的重量为4*(3-1)+1*(3-2)= 9,右边的重量为9*(4-3)= 9,两边重量相等,则这个数便是平衡数。

题目思路:本题可以枚举平衡点,来进行求解,定义一个三维的数组dp[pos][mid][sum],pos表示当前是第几位,mid表示此次枚举的平衡点的位置,sum是平衡点左右两边的重量和,只有在枚举到最后一位时sum = 0,这个数便满足平衡数的条件,需要注意的一点是因为遍历了pos次,所以0便多加了pos-1次,最后要减掉。这里还有个小优化,就是当计算到sum < 0时可以直接return掉,因为当sum < 0之后就说明右边的重量是肯定大于左边了,是肯定不满足条件了。


AC代码如下:

#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define FIN freopen("in.txt","r",stdin)#define fuck(x) cout<<'['<<x<<']'<<endlusing namespace std;typedef long long LL;typedef pair<int,int>pii;const int MX = 20;int dig[MX];LL dp[MX][MX][2000];LL dfs(int pos,int mid,int sum,bool limt){    if(pos == 0) return sum ? 0 : 1;//最后sum = 0时表示满足题目条件,返回1;    if(sum < 0) return 0;    if(!limt && dp[pos][mid][sum] != -1) return dp[pos][mid][sum];    int top = limt ? dig[pos] : 9;    LL ans = 0;    for(int i = 0;i <= top;i++){        ans += dfs(pos-1,mid,sum + (pos-mid-1)*i,limt && i == top);    }    if(!limt) dp[pos][mid][sum] = ans;    return ans;}LL solve(LL x){    int pos = 0;    while(x){        dig[++pos] = x%10;        x /= 10;    }    LL ans = 0;    for(int i = 0;i < pos;i++)        ans += dfs(pos,i,0,true);    return ans-pos;//注意要将多计算的pos减去;}int T;LL x,y;int main(){    scanf("%d",&T);    memset(dp,-1,sizeof(dp));//因为一个数是否为平衡数并不会因为所选的区间改变而改变,所以只需要在最外面初始化一次即可。    while(T--){        scanf("%lld%lld",&x,&y);        printf("%lld\n",solve(y)-solve(x-1));//因为直接算[x,y]区间内的平衡数个数比较麻烦,所以我们可以先算出[0,r],[0,l]内满足条件的数的个数,最后相减便是答案了。    }    return 0;}

原创粉丝点击