隐藏
「HDU3709」Balanced Number - 数位动规 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「HDU3709」Balanced Number - 数位动规

题目大意

    定义一个数若以某个数字作为支点,左右力矩(到支点的距离乘数字大小)相等,则称这个数是平衡的。求区间$[a,b]$中有多少个平衡数。


题目分析

设置状态$f[i,s,p]$表示第$i$位,当前的左右力矩之差为$s$(左为正,右为负),支点在$p$的平衡数个数。
简单的转移一下即可。

注意仅有$0$会被重复统计答案,假若最大长度为$len$,则$0$被统计了$len$次,需要减去$len-1$次。
当然你也可以判一下前导零,若最后有前导零则不计入答案,这样最后少统计了一次,需要$+1$,注意有前导零的时候不能计入$f$数组。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;

inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

int a[25];
LL f[25][1505][25];

LL Dp(int Now,int s,int p,bool up) {
if(Now<0)return s==0;
if(s<0)return 0;
if(!up&&~f[Now][s][p])return f[Now][s][p];
int Limit=up?a[Now]:9;
LL sum=0;
for(int i=0; i<=Limit; i++)sum+=Dp(Now-1,s+(Now-p)*i,p,up&&i==Limit);
if(!up)f[Now][s][p]=sum;
return sum;
}

LL Cal(LL x) {
if(x<0)return 0;
int tot=0;
while(x) {
a[tot++]=x%10;
x/=10;
}
LL sum=0;
for(int i=0; i<tot; i++)sum+=Dp(tot-1,0,i,1);
return sum-tot+1;
}

int main() {
memset(f,-1,sizeof(f));
int t=Get_Int();
while(t--) {
LL x=Get_Int(),y=Get_Int();
printf("%lld\n",Cal(y)-Cal(x-1));
}
return 0;
}
姥爷们赏瓶冰阔落吧~