题意:给出区间(l,r),找出区间所有符合以下条件的数的个数。
它能被自己所有非零位的数整除。
题解:数位dp,1-9的最小公倍数是2520,所以我们mod2520来保存即可。再用map来保存一下dp到每个位数的当前乘积,防止开太大空间mle。
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
using namespace std;
typedef __int64 ll;
map<ll,ll>sp;
ll digit[20],dp[19][2520][50],cnt=0;
ll dfs(ll pos,ll sum,ll gs,ll lim){
if(pos<=0){
if(gs==0)return 0;
else return sum%gs==0;
}
if(!lim&&dp[pos][sum][sp[gs]]!=-1){
return dp[pos][sum][sp[gs]];
}
ll es=lim?digit[pos]:9;
ll ret=0;
for(ll i=0;i<=es;i++){
ll sg=0;
if(i==0)sg=gs;
else if(gs==0)sg=i;
else{
ll sda=__gcd(i,gs);
sg=gs*i/sda;
}
ret+=dfs(pos-1,(sum*10+i)%2520,sg,lim&&(i==es));
}
if(!lim){
if(sp[gs]==0){
sp[gs]=++cnt;
}
dp[pos][sum][sp[gs]]=ret;
}
return ret;
}
int main(){
int t;
cin>>t;
memset(dp,-1,sizeof(dp));
while(t--){
ll l,r;
cin>>l>>r;
ll len;
len=0;
l--;
while(l){
digit[++len]=l%10;
l/=10;
}
ll sol1=dfs(len,0,0,1);
len=0;
while(r){
digit[++len]=r%10;
r/=10;
}
ll sol2=dfs(len,0,0,1);
cout<<sol2-sol1<<endl;
}
return 0;
}