【hdu3709】Balanced Number

  • 数位dp重修系列第三题

题目翻译

定义一个数是平衡的,当且仅当把它看成一个杠杆,存在一个支点使它平衡。

例如4139。当3作为支点时,左边的力矩是4×2+1×1=9,右边的力矩是9×1=9。所以这个杠杆是平衡的,4139是平衡数。

询问[L,R]中有多少个平衡数。

$0≤L≤R≤10^{18}$

题解

设f[i][j][k]表示前i位,支点为j,当前力矩位k的方案数

则f[i][j][k]=f[i-1][j][k+(i-j)*x]

注意在枚举支点的过程中,0被算了tot次,要减去

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
#include<bits/stdc++.h>
#define FILE "read"
using namespace std;
typedef long long ll;
ll f[20][20][1550];
int num[20];
inline ll read(){
ll x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
ll dfs(int i,int j,ll k,int flag){
if(k<0) return 0;
if(!i) return k==0;
if(f[i][j][k]!=-1&&!flag) return f[i][j][k];
ll temp=0;
for(int x=0;x<=(flag?num[i]:9);++x)
temp+=dfs(i-1,j,k+(i-j)*x,flag&&x==num[i]);
if(!flag) f[i][j][k]=temp;
return temp;
}
ll get(ll x){
int tot=0; ll ans=0; memset(f,-1,sizeof(f));
while(x) num[++tot]=x%10,x/=10;
for(int i=1;i<=tot;++i) ans+=dfs(tot,i,0,1);
return ans-tot+1;//计算每个平衡点时,0都被计算了一次,要去重
}
void solve(){
ll l=read(),r=read();
printf("%lld\n",get(r)-(l?get(l-1):0));
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
for(int T=read();T;--T) solve();
return 0;
}
文章目录
  1. 1. 题目翻译
  2. 2. 题解
,