版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83010977
正题
求[x,y]中能被自己所有非零位数整除的数的个数。
题目很直接。我们首先考虑数位Dp。
想到影响答案的有三个东西,第几位,前面选了什么数字,前面的权值是多少。
但是很明显第三位是很大的,long long,所以存不下。
想到前面权值的多少只跟它 mod 2520(1到9的lcm)有关,因为把这个数拆成2520*k+b的形式,2520是可以整除1到9的任何数的,所以关键就看b能否整除。
那么数组就很明显了,表示第i位,1到9状态压缩为j,前面选的数是k,没有满的答案。
直接递推,最后判断一下即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int T;
long long a,b;
int g[20];
long long mod=2520;
long long f[20][1024][2520];
long long op[20];
int len=0;
long long Dp(int x,bool tf,int p,int now){
if(x==0){
for(int i=1;i<=9;i++) if((p&(1<<i-1))!=0 && now%i!=0) return 0;
return 1;
}
if(tf==false && f[x][p][now]!=-1) return f[x][p][now];
int end=tf==true?g[x]:9;
long long res=0;
for(int i=1;i<=end;i++)
res+=Dp(x-1,tf&&i==end,p|(1<<i-1),(now+i*op[x-1])%mod);
res+=Dp(x-1,tf&&end==0,p,now);
if(tf==false) f[x][p][now]=res;
return res;
}
long long solve(long long x){
len=0;
while(x){
g[++len]=x%10;
x/=10;
}
return Dp(len,1,0,0);
}
int main(){
op[0]=1;
for(int i=1;i<=19;i++) op[i]=op[i-1]*10%mod;
memset(f,-1,sizeof(f));
scanf("%d",&T);
while(T--){
scanf("%lld %lld",&a,&b);
printf("%lld\n",solve(b)-solve(a-1));
}
}