Hdu 3709 Balanced Number
题意:整数域上,给一个闭区间,问你闭区间内balance数有多少个?区间规模[0,10^18]
Balance数: 以这个数的某一位为天平中心,每个数字大小为重量,数字距离中心的距离为力臂,使得天平平衡,则这个数称为Balance数。比如:4139,如果天平中心放在3这一位,天平左侧: 4*2 + 1*1 = 9;天平右侧:1*9=9;因此天平平衡,所以4139是balance数。
解题思路:
基本框架是数位DP,规模太大。难点在于如何判断一个数是不是balance数。这里我着重分析如何判定部分。
区间分解:[X, Y] = [0, Y] - [0, X-1]
对于小于X的数,我们需要判定它是不是balance数:
digit(i)表示数的第i个数字
数字和:sdig=sum(digit(i)) {i=1..n }
数字位权和:snum=sum(i*digit(i)) {i=1..n}
每一次判断数是不是平衡的,就看snum%sdig是不是0.
因为:如果将轴放在最高位的左边,那么天平将偏向一边,我们定义一个天平平衡度,就是snum.
如果天平平衡,那么snum=0
每次从高位向低位移动轴的时候,平衡度减小sdig,这个画画图就知道。于是判断能否整除就可以知道数字是不是平衡的。
Code:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
#define inf 1000000000
int d[25];
__int64 dp[18][180][1600];
//int dp[18][18*9+1][9*9*17+1];
__int64 dfs(int i,int sdig,int snum,bool flag)
{
//准备枚举i位时,数字和sdig,数的位权和snum
if(i==0)
if(sdig==0 || snum%sdig==0)return 1;
else return 0;
if(!flag && dp[i-1][sdig][snum]!=-1)
return dp[i-1][sdig][snum];
int limit;
__int64 sum;
if(flag)limit=d[i];
else limit=9;
sum=0;
for(int s=0;s<=limit;s++)
sum+=dfs(i-1,sdig+s,snum+s*(i-1),flag&&s==limit);
if(!flag) dp[i-1][sdig][snum]=sum;
return sum;
}
int main()
{
int T;
__int64 A,B,SA,SB;
cin>>T;
memset(dp,-1,sizeof(dp));
while(T--)
{
cin>>A>>B;
A--;
d[0]=0;
do{ d[++d[0]]=A%10; A/=10;}while(A);
SA=dfs(d[0],0,0,1);
d[0]=0;
do{ d[++d[0]]=B%10; B/=10;}while(B);
SB=dfs(d[0],0,0,1);
cout<<SB-SA<<endl;
}
return 0;
}