HDU3709 Balanced Number

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

题目大意:

  定义一个数字上的某一个数位作为中枢,其他数位上的数乘上该数位到中枢的距离称为该数位上的权值。

  问在 \([x,y]\) 中满足下述条件的数有多少个:

  即能够在数字上任取一个数位作为中枢,使得中枢左右所有数位的权值和相等。

知识点:  数位DP

解题思路:

  首先,对于每一个数(先不考虑 \(0\) ),如果它能找到满足条件的中枢,那么这种中枢只有一个。粗略证明:假设一个数有两个满足条件的不同位置的中枢,设为 \(p_1\), \(p_2\),\(p_1<p_2\),则 \(p_1\) 对应的左边的权值和必定小于或等于 \(p_2\) 对应的左边权值和,\(p_1\) 对应的右边的权值和必定大于或等于 \(p_2\) 对应的右边权值和,这两者都相等当且仅当这个数为 \(0\),但我们暂时不考虑 \(0\),故假设不成立,原命题得证。

  基于以上的结论,我们可以枚举中枢的位置,各自走一次 \(DFS\) 即可得出答案。

  另,无论中枢的位置在哪里,\(0\) 显然都会被计为满足条件,故要注意去重。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 ll dp[20][20][10000];   //dp[第几位是中点][位置][sum值]
 6 int a[20];
 7 ll dfs(int pos,int zhong,int sum,bool limit){
 8     if(pos==-1)
 9         return sum==0?1:0;
10     if(sum<0)   return 0;
11     if(!limit&&dp[zhong][pos][sum]!=-1) return dp[zhong][pos][sum];
12     int up=limit?a[pos]:9;
13     ll ans=0;
14     for(int i=0;i<=up;i++){
15         int tsum=(pos-zhong)*i+sum;
16         ans+=dfs(pos-1,zhong,tsum,limit&&i==a[pos]);
17     }
18     if(!limit)  dp[zhong][pos][sum]=ans;
19     return ans;
20 }
21 ll solve(ll x){
22     if(x<0) return 0;
23     int pos=0;
24     while(x){
25         a[pos++]=x%10;
26         x/=10;
27     }
28     ll ret=0;
29     for(int i=0;i<pos;i++){
30         ret+=dfs(pos-1,i,0,true);
31         ret--;
32     }
33     return ret+1;
34 }
35 int main(){
36     memset(dp,-1,sizeof(dp));
37     int T;
38     ll x,y;
39     scanf("%d",&T);
40     while(T--){
41         scanf("%lld%lld",&x,&y);
42         printf("%lld\n",solve(y)-solve(x-1));
43     }
44     return 0;
45 }

 

posted @ 2018-03-11 12:21  Blogggggg  阅读(137)  评论(0编辑  收藏  举报