Balanced Number HDU - 3709 数位dp

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long dp[30][30][3000];
int num[30];
long long dfs(int pos,int center,int sum,bool flag) {
	//如果遍历到最后以为了
	if(pos==0)
		//判断和是否位0
		return sum==0;
	if(sum<0)
		return 0;
	//如果最大值没有被使用
	//且之前遍历过,那么就直接拿来调用
	if(!flag&&dp[pos][center][sum]!=-1)
		return dp[pos][center][sum];
	long long ans=0;
	//判断是否为最大值
	//类似于限制
	//上一位是否位最大值,如果是的话,那么当前位只能取到num[pos],如果不是,那么0到9都能
	//
	int maxn=flag?num[pos]:9;
	for(int i=0; i<=maxn; i++) {
		//		位数减1
		//			  中心不变
		//		当前位置的贡献值,如果在中心右边,就是正数,在左边,就是负数,最终答案如果是0,就是合理情况
		//										最大值限制
		ans+=dfs(pos-1,center,sum+i*(pos-center),i==maxn&&flag);
	}//pos-center
	//如果当前没限制
	if(!flag)
		//记录方案
		dp[pos][center][sum]=ans;
	return ans;
}
long long cal(long long x) {
	long long ans=0;
	int pos=0;
	//把每一位拿出来
	while(x) {
		num[++pos]=x%10;
		x/=10;
	}
	//枚举中心的位置
	for(int i=1; i<=pos; i++)
		//当前枚举的到的长度,
		//			轴的位置
		//			  力矩和
		//				最大位是否使用
		ans+=dfs(pos,i,0,1);
	//答案要去掉重复的0!!!(因为支点在每一位都有0满足情况)
	return ans-pos+1;
}
int main() {
	int t;
	long long n,m;
	memset(dp,-1,sizeof(dp));
	scanf("%d",&t);
	while(t--) {
		scanf("%I64d%I64d",&n,&m);
		printf("%I64d\n",cal(m)-cal(n-1));
	}
	return 0;
}
posted @ 2020-03-15 20:55  晴屿  阅读(95)  评论(0编辑  收藏  举报