首先看到数据范围, 9 e 18 9e18 9e18,再看题面,很明显的数位DP。
需要注意的地方:
0
0
0 可以整除所有数。。。
答案可能会大于
18
18
18 位,所以
i
n
t
int
int 存不下!!!
分析
然后我们先确定 d p dp dp 数组的下标,显然是一个三维的数组 —— d p [ p o s ] [ r a r ] [ s t a ] dp[pos][rar][sta] dp[pos][rar][sta]。
我们用 p o s pos pos 表示当前位数, r a r rar rar 压缩一个状态,当先数位上有哪些数字,用 s t a sta sta 来表示原数。
但很显然,直接存 s t a sta sta 是存不下的,于是我们想到了 m o d mod mod,那么我们将模数设为什么好呢?—— 1 9 1~9 1 9 的 l c m lcm lcm 也就是 2520 2520 2520。
于是我定义了 d p [ 20 ] [ 1024 ] [ 2521 ] dp[20][1024][2521] dp[20][1024][2521],经过计算后发现大概是 51 , 630 , 080 51,630,080 51,630,080,也就是说只要开 i n t int int 就不会炸空间,于是我就很高兴的开了 i n t int int 。。。
“于是它飞快地 WA 掉了”—— 某dalao
后来发现了答案可能很大。。。其实将
2520
2520
2520 进行离散化,但我 实在太弱了。。。没想到 发现对于
0
0
0 和
1
1
1 都是可以不计入状态中的,因为任意一个数(非
0
0
0 )都可以被它们整除。所以我们就可以将第二位的上限改为
512
512
512,大小变成了原来的
1
2
\frac{1}{2}
21 我们就可以开
l
o
n
g
l
o
n
g
long long
longlong 啦。 #define int long long
然后我们确定 d f s dfs dfs 中的形参,很显然就是 p o s , r a r , s t a , l i m i t pos,rar,sta,limit pos,rar,sta,limit, l i m i t limit limit 表示是否到达上限。至于前导零的判断,本题并不需要。
那么我们就有两种转移,当 i ≤ 1 i \leq 1 i≤1 时:( u p up up 表示上限)
tem += dfs(pos - 1, rar, (sta * 10 + i) % MOD, (i == up) && limit);
而当
2
≤
i
2 \leq i
2≤i 时:( 不会打 $ latex $ 的大于等于 QAQ
tem += dfs(pos - 1, rar | (1 << (i - 2)), (sta * 10 + i) % MOD, (i == up) && limit);
下面放上代码(实测 A C AC AC
#include<bits/stdc++.h>
#define int long long
#define inc(i) (++ (i))
#define dec(i) (-- (i))
#define Rep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i <= i##Limit ; inc(i))
#define Dep(i, a, b) for(register int i = (a) , i##Limit = (b) ; i >= i##Limit ; dec(i))
using namespace std;
const int MOD = 2520;
int a, b, T;
int res[21], dp[20][512][2521];
int dfs(int pos, int rar, int sta, bool limit) {
if(!pos) {
int num = 1;
while(rar) {
inc(num);
if(rar & 1 && sta % num != 0) return 0;
rar >>= 1;
}
return 1;
}
if(dp[pos][rar][sta] != -1 && !limit) return dp[pos][rar][sta];
int up, tem = 0;
if(limit) up = res[pos];
else up = 9;
Rep(i,0,up) {
if(i <= 1) tem += dfs(pos - 1, rar, (sta * 10 + i) % MOD, (i == up) && limit);
else tem += dfs(pos - 1, rar | (1 << (i - 2)), (sta * 10 + i) % MOD, (i == up) && limit);
}
if(!limit) dp[pos][rar][sta] = tem;
return tem;
}
int solve(int x) {
int pos = 0;
while(x) {
res[inc(pos)] = x % 10;
x /= 10;
}
return dfs(pos, 0, 0, 1);
}
signed main()
{
cin>>T;
memset(dp, -1, sizeof(dp));
while(T --) {
cin>>a>>b;
printf("%lld\n", solve(b) - solve(a - 1));
}
return 0;
}