隐藏
「Hoj1983」Beautiful numbers - 数位动规 | Bill Yang's Blog

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

0%

「Hoj1983」Beautiful numbers - 数位动规

题目大意

    给定$L,R$,求$[L,R]$中能被它所有非零数位整除的数的个数。


题目分析

数位动规。
容易发现$lcm(1,2,3,4,5,6,7,8,9)=2520$,它们任意一个集合的$lcm$只有$48$种。
故用一次搜索对所有的$lcm$编号,设置状态$f[i,j,k]$表示第$i$位,前面的数位形成的数$\bmod\,2520=j$,非零数位的$lcm$编号为$k$,转移即可。


代码

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
64
65
66
67
68
69
70
71
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#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 cnt=0,tot,a[25],list[605],Hash[3005];
LL f[25][2555][55];

LL Dp(int Now,int num,int lcm,bool up) {
if(Now<0)return lcm&&(num%list[lcm]==0);
if(!up&&~f[Now][num][lcm])return f[Now][num][lcm];
int Limit=up?a[Now]:9;
LL sum=0;
for(int i=0; i<=Limit; i++) {
if(i)sum+=Dp(Now-1,(num*10+i)%2520,lcm?Hash[list[lcm]/__gcd(list[lcm],i)*i]:i,up&&i==Limit);
else sum+=Dp(Now-1,num*10%2520,lcm,up&&i==Limit);
}
if(!up)f[Now][num][lcm]=sum;
return sum;
}

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

void Dfs(int Now,int lcm) {
if(Now>9)return;
int New=lcm/__gcd(lcm,Now)*Now;
list[++cnt]=New;
Dfs(Now+1,New);
Dfs(Now+1,lcm);
}

LL x,y;

int main() {
memset(f,-1,sizeof(f));
Dfs(1,1);
sort(list+1,list+cnt+1);
cnt=unique(list+1,list+cnt+1)-(list+1);
for(int i=1; i<=cnt; i++)Hash[list[i]]=i;
while(scanf("%lld%lld",&x,&y)!=EOF)printf("%lld\n",Cal(y)-Cal(x-1));
return 0;
}
姥爷们赏瓶冰阔落吧~