题意是:求 [l,r] 区间内完美数的个数,完美数的定义:这个数能是所有位数的倍数,比如42,42是4的倍数,也是2的倍数。
考虑数位DP,
LL dfs(int pos,int now,int lc,int limit) 表示pos为,这个数为now,所有位数的LCM为lc,上限为limit。
那么边界的情况就是 now%lc ==0才返回1
注意数据的输入和输出要用long long 和I64d
还有一个问题,根据前面的DFS函数,记忆化DP为dp[20][2520][2520],2520为1-9的LCM,会MLE,但是在第三维的纪录LCM中不会出现2520种,只会出现大概几十种吧,这里我开到100就能过,那么每生成一个新的LCM,离散化,这里用的是use[]数组,写在DFS函数中,就不用单独的预处理了。
还有就是注意细节吧,我把数组开为dp[20][2520][100],错了好几次,2520访问不到,但是没有返回RE,返回了WA,喵了个咪的。
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<set>
#include<iostream>
using namespace std;
#define INF 0x7f7f7f7f
#define LL long long
LL dp[20][2525][100]; //离散化后的数组
int use[2525];
int a[25],cnt;
int gcd(int a,int b)
{
while(b!=0)
{
a=a%b;
swap(a,b);
}
return a;
}
int lcm(int a,int b)
{
return (a*b)/gcd(a,b);
}
LL dfs(int pos,int now,int lc,int limit)
{
if(use[lc]==0) //便找边离散化
use[lc]=cnt++;
if(pos==-1)
{
if(now%lc==0) //如果这个数%所有位数的lcm就返回1
return 1;
return 0;
}
if(!limit&&dp[pos][now][use[lc]]!=-1)
return dp[pos][now][use[lc]];
int up=limit ? a[pos]:9;
LL ret=0;
for(int i=0;i<=up;i++)
{
if(i!=0)
ret+=dfs(pos-1,(now*10+i)%2520,lcm(lc,i),limit&&i==a[pos]); //如果i==0,那么LCM(i,lc)为出问题
else
ret+=dfs(pos-1,(now*10+i)%2520,lc,limit&&i==a[pos]);
}
if(!limit)
dp[pos][now][use[lc]]=ret;
return ret;
}
LL solve(LL x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,1,true);
}
int main()
{
int t;
cnt=0;
memset(use,0,sizeof(use));
memset(dp,-1,sizeof(dp));
scanf("%d",&t);
while(t--)
{
LL l,r;
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",solve(r)-solve(l-1));
}
return 0;
}