正题
题目链接:https://www.luogu.com.cn/problem/CF55D
题目大意
求[l,r][l,r][l,r]中有多少个数使得它可以被它的所有非000位整除。
解题思路
因为这些数的lcmlcmlcm一定是lcm(1,2,3,4,5,6,7,8,9,10)=2520lcm(1,2,3,4,5,6,7,8,9,10)=2520lcm(1,2,3,4,5,6,7,8,9,10)=2520的约数,所以我们只需要记录这个数%2520\% 2520%2520的值即可,设fi,j,kf_{i,j,k}fi,j,k表示到第iii位,这个数字%2520\% 2520%2520的值为jjj,当前非000数的lcmlcmlcm为kkk时的结果,当然kkk这一维要离散化。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const ll P=2520;
ll t,f[20][50][P],a[20],rev[P+10],cnt;
ll gcd(ll x,ll y)
{return (!y)?x:gcd(y,x%y);}
ll dfs(ll x,ll lcm,ll v,bool sp){if(x<0)return (v%lcm==0);if(!sp&&f[x][rev[lcm]][v]>=0)return f[x][rev[lcm]][v];ll sum=0,lim=(sp==1)?a[x]:9;for(ll i=0;i<=lim;i++){if(!i)sum+=dfs(x-1,lcm,v*10%P,sp&(i==lim));else sum+=dfs(x-1,lcm*i/gcd(lcm,i),(v*10+i)%P,sp&(i==lim));}if(sp)return sum;return f[x][rev[lcm]][v]=sum;
}
ll get(long long x){ll i=0;if(!x)return 1;for(i=0;x;x/=10,i++)a[i]=x%10;return dfs(i-1,1,0,1);
}
int main()
{cin>>t; memset(f,-1,sizeof(f));for(int i=1;i<=P;i++)if(P%i==0)rev[i]=++cnt;while(t--){ll l,r;cin>>l>>r;cout<<get(r)-get(l-1)<<endl;}return 0;
}