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次。。记得减去。

/* ***********************************************
Author :111qqz
Created Time :2016年03月17日 星期四 17时08分59秒
File Name :code/hdu/3709.cpp
************************************************ */

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair

using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
LL l,r;
int T;
int digit[30];
LL dp[20][2000][20];  //窝要判断左边和右边是否相等,并不需要分别统计两边,只要把数值带上符号,统计左右两边的和即可。
                        //如果相等,那么和为0.这样能节省很多空间。
LL dfs( int pos,int sum ,int pivot,bool limit) 
{			//不用考虑前导0,因为前导0的存在并不会对答案有任何贡献.
    if (pos==0) return sum==0;
    if (sum<0) return 0; //由于sum是递减的。。所以sum一旦小于0绝对药丸。。。肯定对答案没贡献。
			//也算作一个剪枝..
    if (!limit&&dp[pos][sum][pivot]!=-1) return dp[pos][sum][pivot];

    int mx = limit?digit[pos]:9;
    LL res = 0LL ;
    for ( int i = 0 ; i <= mx ; i++)
    {
	res+=dfs(pos-1,sum+(pos-pivot)*i,pivot,limit&&i==mx);
    }

   // cout<<"res:"<<res<<endl;  
    return limit?res:dp[pos][sum][pivot]=res;
}
LL solve (LL n)
{
   // if (n<0) return 0;
    LL len = 0;
    ms ( digit , 0 );
    while (n)
    {
	digit[++len] =  n % 10;
	n /= 10;
    }

    LL res = 0LL ;
    for ( int piv = 1 ; piv <= len  ; piv++)  //pivot要从1开始枚举到len。因为个位数也是满足条件的数(两边都为0,相等)
    {
	res += dfs (len,0,piv,true);
//	cout<<"res:"<<res<<endl;
    }

    return res-(len-1); //0,00,000,0000都是满足条件的,然而其实他们是一个数,多算了len-1次。
}
int main()
{
	#ifndef  ONLINE_JUDGE 
	freopen("code/in.txt","r",stdin);
  #endif

	ios::sync_with_stdio(false);
	int T;
	cin>>T;
	ms(dp,-1);
	while (T--)
	{
	    cin>>l>>r;
	    LL ans = solve (r) - solve (l-1);
	  //  cout<<"-1:"<<solve(-1)<<endl;
	    cout<<ans<<endl;
	}

  #ifndef ONLINE_JUDGE  
  fclose(stdin);
  #endif
    return 0;
}