题意:
求区间内满足能被每位非零数整除数的个数。数据范围:9*10^18
思路来源于:男神博客
思路:
lcm(1,2,3,4,5,6,7,8,9)=2^3*3^2*5*7=2520 公约数的总个数为4*3*2*2=48个
a%b=0 可推出 a%(k*b)%b=0。
所以可以先对2520取模,再对各位出现数字的lcm取模。
可以用记忆化搜索 dfs(pos,r,lcm,flag) 表示到当前位,前缀模2520为r,前缀的最小公倍数为lcm,上界标志,枚举这一位选什么来转移,递归算答案。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#include <sstream>
#define maxn 100005
#define MAXN 100005
#define mod 2520
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-8
typedef long long ll;
using namespace std;
ll n,m,ans,tot,cnt;
ll dig[21],dp[21][2525][50],mp[2525],fac[21];
ll gcd(ll x,ll y)
{
if(y==0) return x;
return gcd(y,x%y);
}
ll LCM(ll x,ll y)
{
if(y==0) return x;
return x/gcd(x,y)*y;
}
ll dfs(ll pos,ll r,ll lcm,bool flag)
{
if(pos==0)
{
if(r%lcm==0) return 1;
return 0;
}
if(!flag&&dp[pos][r][mp[lcm]]!=-1) return dp[pos][r][mp[lcm]];
ll i,j,t,best=0,ed,r1,lcm1;
if(flag) ed=dig[pos];
else ed=9;
for(i=0;i<=ed;i++)
{
r1=(r+i*fac[pos-1])%mod;
lcm1=LCM(lcm,i);
t=dfs(pos-1,r1,lcm1,flag&&i==ed);
best+=t;
}
if(!flag) dp[pos][r][mp[lcm]]=best;
return best;
}
ll solve(ll x)
{
ll i,j,t,tot=0;
while(x)
{
dig[++tot]=x%10;
x/=10;
}
// printf("");
t=dfs(tot,0,1,1);
return t;
}
int main()
{
ll i,j,t,le,ri,a2,a3,a5,a7;
cnt=0;
for(i=0;i<=3;i++)
{
if(i==0) a2=1;
else a2*=2;
for(j=0;j<=2;j++)
{
if(j==0) a3=1;
else a3*=3;
for(ll p=0;p<=1;p++)
{
if(p==0) a5=1;
else a5*=5;
for(ll q=0;q<=1;q++)
{
if(q==0) a7=1;
else a7*=7;
mp[a2*a3*a5*a7]=++cnt;
}
a7=1;
}
a5=1;
}
a3=1;
}
fac[0]=1;
for(i=1;i<=20;i++)
{
fac[i]=fac[i-1]*10;
}
memset(dp,-1,sizeof(dp));
cin>>t;
while(t--)
{
cin>>le>>ri;
ans=solve(ri)-solve(le-1);
cout<<ans<<endl;
}
return 0;
}