C - Balanced Number HDU - 3709 (数位dp)
题目链接:https://cn.vjudge.net/contest/278036#problem/C
题目大意:手首先是T组数据,然后每一次输入两个数l,r,求这个区间里面满足以某个数字为中心的两侧力矩和相等的个数,举个例子,4139,我们如果把3当做对称点,那么力矩和的计算方式= (1-3)*4 + 3*(2-3)+9*(4-3)=0,这个数是满足题目条件的。
具体思路:模板题,我们用一个三维dp储存结果,dp[len][pos][sum],len代表的是当前处理的是第几位,pos代表的是当前枚举的是第几个位置,sum代表的是当前的力矩和。
另外,这个题去重的情况只有长度是不同0,比如说000和0其实是一个数,这个时候需要去重。不存在一个数存在两个对称点并且力矩为0的情况,假设当前的数存在满足情况的对称点,那么如果他如果的左边还有对称点的话,左边的力矩最多保持不变,这个时候右边的力矩肯定会增加,右边类似,所以不存在一个数存在两个满足情况的力矩。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<stdio.h> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 # define ll long long 8 const int maxn = 10+10; 9 ll dig[maxn],dp[maxn][maxn][3000]; 10 ll dfs(ll len,ll pos,ll sum,bool fp) 11 { 12 if(len==0) 13 return sum==0; 14 if(sum<0)//如果小于0的话,再往右也不会增加了,所以这个时候直接不用再往下走了。 15 return 0; 16 if(!fp&&dp[len][pos][sum]!=-1) 17 return dp[len][pos][sum]; 18 ll ans=0,fmax=fp?dig[len]:9; 19 for(int i=0; i<=fmax; i++) 20 { 21 ans+=dfs(len-1,pos,(len-pos)*i+sum,fp&i==fmax); 22 } 23 if(!fp) 24 dp[len][pos][sum]=ans; 25 return ans; 26 } 27 ll cal(ll n) 28 { 29 memset(dp,-1,sizeof(dp)); 30 int num=0; 31 while(n) 32 { 33 dig[++num]=n%10; 34 n/=10; 35 } 36 ll sum=0; 37 for(ll i=1; i<=num; i++) 38 { 39 sum+=dfs(num,i,0,1); 40 } 41 return sum-num+1;//去重的情况,因为0000和0和0000都是一个数。 42 } 43 int main() 44 { 45 int T; 46 scanf("%d",&T); 47 while(T--) 48 { 49 ll n,m; 50 scanf("%lld %lld",&n,&m); 51 printf("%lld\n",cal(m)-cal(n-1)); 52 } 53 return 0; 54 } 55