题目链接: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 }