求区间内本身值是十进制数字之和的倍数的数有多少 1-9的lcm是2520 可以想到将数本身的值对2520取模作为第一个状态 十进制数字的lcm作为第二个状态 来进行数位DP 但是空间爆炸
其实1-9所有能组成的lcm去重后并不多 大约50左右 将第二维离散化一下即可
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod=2520;
const int maxn=50;
const int maxm=3e3+10;
ll dp[maxn][maxm][maxn];
ll pre[maxn];
int bit[maxn],mp[maxm];
void init()
{
int i;
memset(dp,-1,sizeof(dp));
pre[0]=1;
for(i=1;i<=18;i++){
pre[i]=10ll*pre[i-1];
}
for(i=1;i<=mod;i++){
mp[i]=mp[i-1];
if(mod%i==0) mp[i]++;
}
}
int getlcm(int a,int b)
{
return (a*b)/__gcd(a,b);
}
ll dfs(int pos,int sta,int lcm,int limit)
{
ll res;
int up,i,tmp;
if(pos==-1){
return sta%lcm==0;
}
if(!limit&&dp[pos][sta][mp[lcm]]!=-1) return dp[pos][sta][mp[lcm]];
if(limit) up=bit[pos];
else up=9;
res=0;
for(i=0;i<=up;i++){
if(i==0) tmp=lcm;
else tmp=getlcm(lcm,i);
res+=dfs(pos-1,(sta+(ll)i*pre[pos])%mod,tmp,limit&&i==bit[pos]);
}
if(!limit) dp[pos][sta][mp[lcm]]=res;
return res;
}
ll solve(ll val)
{
int n;
n=0;
while(val>0){
bit[n++]=val%10;
val/=10;
}
return dfs(n-1,0,1,1);
}
int main()
{
ll l,r;
int t;
init();
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}