想了半天,总算想出来了。这题刚上来的思路很明显是11维DP。。但是明显不可取。。
这题的关键在于只要两个数前面的拥有的数字是一样的,而且此时与其最小公倍数的模是一样的,那么这时候就可以认为对所有的数字取模都是相等的,那么后面的总情况数属于完美数的情况也是相同的。
只要想到这步的话,那么基本思路就出来了,我第一次居然脑残的记录lcm与模2520(2到9的最小公倍数),首先lcm相同并不代表出现的数字相同先不说,仅仅这个最大值就太大了,lcm最大是2520,这样的话就需要开一个20*2520*2520的数组,我一看给的内存挺大的,就这么写了,然后提交。。果然MLE on TEST 1.。。。
然后才用的二进制状压记录2到9出现的数,因为0到1不用记录,所以只需要开1<<8大小就可以了。
这样空间复杂度就少了很多。然后就这样一改,果然AC了。
代码如下:
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
using namespace std;
#define LL __int64
#define pi acos(-1.0)
const int mod=2520;
const int INF=0x3f3f3f3f;
const double eqs=1e-8;
LL dp[19][257][2530], c[20], lcm[257];
int gcd(int x, int y)
{
return y==0?x:gcd(y,x%y);
}
int getlcm(int x, int y)
{
if(!x) return y;
return x*y/gcd(x,y);
}
int find1(int x, int y)
{
if(y<=1) return x;
y-=2;
if(x&(1<<y)) return x;
return x|(1<<y);
}
int init()
{
int ans=1;
int i, j;
lcm[0]=1;
for(i=1;i<=255;i++){
ans=1;
for(j=2;j<=9;j++){
if(i&(1<<(j-2))){
ans=getlcm(ans,j);
}
}
lcm[i]=ans;
}
}
LL dfs(int cnt, int maxd, int zero, int z, int mods)
{
if(cnt==-1) return !(mods%lcm[z]);
if(zero&&maxd&&dp[cnt][z][mods]!=-1) return dp[cnt][z][mods];
int i, r=maxd?9:c[cnt];
LL ans=0;
for(i=0;i<=r;i++){
ans+=dfs(cnt-1,maxd||i<r,zero||i,find1(z,i),(mods*10+i)%mod);
}
if(zero&&maxd) dp[cnt][z][mods]=ans;
return ans;
}
LL Cal(LL x)
{
int i, cnt=0;
while(x){
c[cnt++]=x%10;
x/=10;
}
return dfs(cnt-1,0,0,0,0);
}
int main()
{
int t;
LL l, r;
memset(dp,-1,sizeof(dp));
init();
scanf("%d",&t);
while(t--){
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",Cal(r)-Cal(l-1));
}
return 0;
}