题意:给定一个[l, r]区间,求其中该数能被其自身每一位数整除的数的个数。
思路:
显然是数位DP。能整除其自身每一位,即能整除其自身每一位数的最小公倍数。lcm(2,...,9)== 2520。对于一个n位数,我们从第一位开始,扫过n位数字以后判断是否满足条件。dp过程中构成的一个n位数字组成的数,最后只需判断其对这n位数的lcm取模是否为0。显然若为0,则返回1;否则为0。
那么我们就可以存三维的dp数组来进行转移。dp[now][lcm][mod],表示前now位数字,其最小公倍数为lcm,对2520取模为mod的dp值。为什么是对2520取模呢?因为对前n位数字的lcm最大只能为2520,所以dp过程中我们只对2520取模,最后判断的时候才对前n位数字的lcm取模。这样得到转移方程:dp[now][lcm][mod] = sigma(dp[now-1][_lcm][_mod])。其中_lcm和_mod为往后更新一位时得到的新的lcm和mod值。注意这里lcm*mod*now < 20 * 2520 * 2520,显然要爆内存。不过打一下表可以发现2~9的最小公倍数组合最多不超过50种,因此可以哈希一下,这样dp数组就可以只开到dp[20][50][2600]。
由于我们对每一位求的不一定是0~9的所有值。因此dp过程中要判断该值是否到达所求数的临界值。用flag标记,然后每一位进行dp时用“||”更新flag。这样如果前面的now-1位没有达到的话,那么第now位是可以取0~9任意值的。否则的话最大只能取到bit[now]。即对应原数的那一位。
最后计算work(r) - work(l-1)即为答案。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include