[a,b]满足f(i)的数字个数;f(i)与数位相关。考虑数位dp。
简单想法是传当前确定的数位和、还有当前确定的那一部分原数就好了。
然而第一个就算了,第二个根本放不下(不放数组里面的话只靠第一个确定不了状态)
回到问题来。只是“整除”可能有点模糊?
[a,b]中,被自身各数位和整除的数字个数
⇒
\Rightarrow
⇒
C
(
{
  
x
  
∣
  
x
  
m
o
d
  
∑
x
i
  
=
  
0
  
}
)
\frak{C(\{\;x\;|\;x\;mod\;\sum x_i\;=\;0\;\})}
C({x∣xmod∑xi=0})
这么考虑呢?
发现什么了吗?对了,mod。
考虑把相对较小的余数和模数存储进来,这样的话状态是:
f(pos,sum,mod,remainder)
其中pos≤18, sum≤162, mod≤162, remainder<162……是不是有点大?
好像这个爆了空间。时间勉勉强强吧,在能过和不能过中间徘徊。
好像最后的sum就是mod,能不能合并哇?
这样的话就变成了算到pos位,%mod=remainder。要求最后sum=mod。
而且这样正好能够保证原数被状态唯一确定。
注意这样的话有一个mod没有被记录进去,然而mod不同,f也不同。所以每次memset。
实际上这样并没有在时间上合并sum和mod,不过至少空间能过了。时间就卡一卡吧。
记忆化搜索的关系,多剪一下枝的话跑起来估计还勉强吧?
实际上也可以直接枚举最后的数位和sum=mod。
Accepted 5272ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
using namespace std;
long long a,b;
int bit[20];
long long F[20][165][165];
long long dfs(const int &pos, const int &sum, const int &mod, const int &remainder, const bool &limit) {
if(sum - pos * 9 > 0) return 0;
if(!pos && !sum) return !remainder;
if(!limit && F[pos][sum][remainder] != -1) return F[pos][sum][remainder];
int up = limit ? bit[pos] : 9;
if(sum < up) up = sum;
long long ret = 0;
for(int t, i = 0; i <= up; ++i) {
ret += dfs(pos - 1, sum - i, mod, (remainder * 10 + i) % mod, limit && i == up);
}
if(!limit) F[pos][sum][remainder] = ret;
return ret;
}
long long solve(long long &x) {
bit[0] = 0;
while(x) {
bit[++bit[0]] = int(x % 10);
x /= 10;
}
long long ret = 0;
for(int i = 1; i <= 9 * bit[0]; ++i) {
memset(F, -1, sizeof(F));
ret += dfs(bit[0], i, i, 0, true);
}
return ret;
}
int main() {
scanf("%lld%lld", &a, &b);
printf("%lld", solve(b) - solve(--a));
return 0;
}