题意:数位统计,l,r内满足条件的数的个数
条件:这个数的值可以被这个数所有的数位整除
之前做过数位统计,这个数可以被某一个数整除的题,大约就是记录余数作为状态,这个当然也想到了记录余数,但是每次记录对谁的余数是个问题,
想到了数位上能出现的数字只能是0~9,因此求一个lcm(1,2,3....9)=2520,记录对他的余数即可,然后在记录一个前面已经出现的数位的最小公倍数,
但是很傻,没想到会出现的最小倍数并不多,可以离散化。。。。就没弄出来,看了题解恍然大悟。。。。
还有就是这个题应该还是要记一下前导零的,因为按这种统计方法,前面是“0000”的状态和“1111”的状态是重复的 ,都是余数为0,最小公倍数为1
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<map>
#include<vector>
#include<string.h>
using namespace std;
long long dp[20][3000][50],a[200];
int lisan[3000];
const long long mo=2520;
long long gcd(long long x,long long y)
{
return y==0?x:gcd(y,x%y);
}
long long lcm(long long x,long long y)
{
return x*y/gcd(x,y);
}
long long dfs(int pos,int limit,long long yu,long long lcmm,long long tt,int lead)
{
if(pos==-1)
{
return yu%lcmm==0&&!lead;
}
int index=lisan[lcmm];
if(dp[pos][yu][index]!=-1&&!limit&&!lead)
return dp[pos][yu][index];
int up=limit?a[pos]:9;
long long ans=0;
for(int i=0;i<=up;i++)
{
if(i==0)
ans+=dfs(pos-1,limit&&i==a[pos],(yu+tt*i)%mo,lcmm,tt/10,lead&&i==0);
else
ans+=dfs(pos-1,limit&&i==a[pos],(yu+tt*i)%mo,lcm(lcmm,i),tt/10,lead&&i==0);
}
if(dp[pos][yu][index]==-1&&!limit&&!lead)
dp[pos][yu][index]=ans;
return ans;
}
long long solve(long long x)
{
int pos=0;
long long tt=1;
while(x)
{
a[pos++]=x%10;
x/=10;
if(x)
tt*=10;
}
return dfs(pos-1,1,0,1,tt,1);
}
int main()
{
long long l,r;
int T;
int now=0,i,j;
for(i=1;i<=mo;i++)
{
if(mo%i==0)
lisan[i]=now++;
}
cin>>T;
memset(dp,-1,sizeof(dp));
while(T--)
{
scanf("%lld %lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}