hdu 3709 Balanced Number (数位dp)

题目链接 题意:找到某区间中平衡数的个数。所谓平衡数是指,存在某个位置,值得两边的力矩相等。举个例子。。比如14326,如果把4作为中间。。那么左边=11=1 右边=31+22+62=19。。。 思路:枚举中间的pivot。。。注意如果是个位数也是平衡数(就是认为两边的力矩都是0了。。。),所以每一个位置都可能是平衡位置。。枚举的时候从1到len… 一开始我是分别记录两边的值。。非常浪费空间。。。然而发现其实没必要。。我们只关心左边是否相等。。而不关心左右的值到底是多少。。所以可以把两边的值带符号合并成一个值(pivot左边为+,pivot右边为负)。。。如果最后为0。。说明左右相等。。。

以及。。这个值(设为sum)是递减的。。。所以任何时刻如果sum<0。。那么狗带。。算一个剪枝。。而且避免了下标为负。。。

以及,关于前导0的问题。。。有些题目不允许前导0.。。。但是并不是所有不允许前导0的都需要特别处理。。。像这道。。前导0不会导致更新答案。。。所以不用管。。。 但是要注意。。。由于0,00,000,0000都是合法的balanced数。。。然而其实他们是一个数。。多加了len-1次。。记得减去。

 1/* ***********************************************
 2Author :111qqz
 3Created Time :2016年03月17日 星期四 17时08分59秒
 4File Name :code/hdu/3709.cpp
 5************************************************ */
 6
 7#include <cstdio>
 8#include <cstring>
 9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define fst first
20#define sec second
21#define lson l,m,rt<<1
22#define rson m+1,r,rt<<1|1
23#define ms(a,x) memset(a,x,sizeof(a))
24typedef long long LL;
25#define pi pair < int ,int >
26#define MP make_pair
27
28using namespace std;
29const double eps = 1E-8;
30const int dx4[4]={1,0,0,-1};
31const int dy4[4]={0,-1,1,0};
32const int inf = 0x3f3f3f3f;
33LL l,r;
34int T;
35int digit[30];
36LL dp[20][2000][20];  //窝要判断左边和右边是否相等,并不需要分别统计两边,只要把数值带上符号,统计左右两边的和即可。
37                        //如果相等,那么和为0.这样能节省很多空间。
38LL dfs( int pos,int sum ,int pivot,bool limit) 
39{			//不用考虑前导0,因为前导0的存在并不会对答案有任何贡献.
40    if (pos==0) return sum==0;
41    if (sum<0) return 0; //由于sum是递减的。。所以sum一旦小于0绝对药丸。。。肯定对答案没贡献。
42			//也算作一个剪枝..
43    if (!limit&&dp[pos][sum][pivot]!=-1) return dp[pos][sum][pivot];
44
45    int mx = limit?digit[pos]:9;
46    LL res = 0LL ;
47    for ( int i = 0 ; i <= mx ; i++)
48    {
49	res+=dfs(pos-1,sum+(pos-pivot)*i,pivot,limit&&i==mx);
50    }
51
52   // cout<<"res:"<<res<<endl;  
53    return limit?res:dp[pos][sum][pivot]=res;
54}
55LL solve (LL n)
56{
57   // if (n<0) return 0;
58    LL len = 0;
59    ms ( digit , 0 );
60    while (n)
61    {
62	digit[++len] =  n % 10;
63	n /= 10;
64    }
65
66    LL res = 0LL ;
67    for ( int piv = 1 ; piv <= len  ; piv++)  //pivot要从1开始枚举到len。因为个位数也是满足条件的数(两边都为0,相等)
68    {
69	res += dfs (len,0,piv,true);
70//	cout<<"res:"<<res<<endl;
71    }
72
73    return res-(len-1); //0,00,000,0000都是满足条件的,然而其实他们是一个数,多算了len-1次。
74}
75int main()
76{
77	#ifndef  ONLINE_JUDGE 
78	freopen("code/in.txt","r",stdin);
79  #endif
80
81	ios::sync_with_stdio(false);
82	int T;
83	cin>>T;
84	ms(dp,-1);
85	while (T--)
86	{
87	    cin>>l>>r;
88	    LL ans = solve (r) - solve (l-1);
89	  //  cout<<"-1:"<<solve(-1)<<endl;
90	    cout<<ans<<endl;
91	}
92
93  #ifndef ONLINE_JUDGE  
94  fclose(stdin);
95  #endif
96    return 0;
97}