本文主要内容:数位DP例题
数位DP
主要有两种方法,填数法和记搜。这里主要研究记搜的实现;
模板
相比于填数法,记搜的优点在于有固定的模板,实现较容易;
缺点在于需要很多 $ memset $,常数较大,容易被卡;
下面通过几道例题来了解记搜模板;
一 $ haha $ 数
设记搜各参数如下:
long long dfs(int x, int gcd, bool limit, int st)
$ gcd $ 代表各位数字的最小公倍数,$ limit $ 代表当前位有没有到达最高位限制,$ st $ 代表现在的数 $ mod \ 2520 $ 的结果($ 2520 $ 是数字$ 1 \ to \ 9 $ 的和);
$ gcd $ 可以离散化($ 2520 $ 的因数最多只有不到 $ 50 $ 个);
long long dfs(int x, int gcd, bool limit, int st) {
if (x > cnt) return st % gcd == 0;
if (!limit && f[cnt - x + 1][vis[gcd]][st] != -1) return f[cnt - x + 1][vis[gcd]][st];
int res = limit ? a[cnt - x + 1] : 9; //判断现在的限制;
long long ret = 0;
for (register int i = 0; i <= res; i++) {
if (i == 0) ret += dfs(x + 1, gcd, limit && i == res, st * 10 % mod); //特判0;
else ret += dfs(x + 1, gcd * i / __gcd(gcd, i), limit && i == res, (st * 10 + i) % mod);
}
return limit ? ret : f[cnt - x + 1][vis[gcd]][st] = ret;
}
也是水了一篇