51nod-1232: 完美数

【传送门:51nod-1232


简要题意:

  完美数定义:一个数能够被它每一位非零的数整除,例如:11,12,15,但13就不是完美数,因为13不能被3整除

  给出T组询问,每组询问输入l,r,输出l到r中有多少个完美数


题解:

  首先很容易想到只要当前数被每一位所有非零的数的lcm整除就好了

  实际上最大的lcm只有2520,而且只能够构成48个不同lcm的值

  那么就可以利用这个来节省空间了,将lcm离散编号

  设f[i][j][k]为第i位已经填好数字后,当前构成的数%2520=j,且当前数位的数的lcm的离散编号为k

  然后直接记忆化搜索就行了


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
LL f[21][3100][51];
int p[3100],Mod=2520;
void pre()
{
    int k=0;p[0]=0;
    for(int i=1;i<=Mod;i++) if(Mod%i==0) p[i]=++k;
}
int cnt[21],tot;
int gcd(int a,int b)
{
    if(a==0) return b;
    else return gcd(b%a,a);
}
int getd(int a,int b)
{
    if(a==0) return b;
    if(b==0) return a;
    return a*b/gcd(a,b);
}
LL dfs(int tp,int x,int d1,int d2)
{
    if(x==1)
    {
        if(d2==0) return 0;
        return d1%d2==0;
    }
    if(tp==0&&f[x][d1][p[d2]]!=-1) return f[x][d1][p[d2]];
    if(tp==0)
    {
        f[x][d1][p[d2]]=0;
        for(int i=0;i<=9;i++)
        {
            if(i==0) f[x][d1][p[d2]]+=dfs(tp,x-1,(d1*10+i)%Mod,d2);
            else f[x][d1][p[d2]]+=dfs(tp,x-1,(d1*10+i)%Mod,getd(d2,i));
        }
        return f[x][d1][p[d2]];
    }
    else
    {
        LL ans=0;
        for(int i=0;i<=cnt[x-1];i++)
        {
            if(cnt[x-1]==0) ans+=dfs(tp,x-1,(d1*10+i)%Mod,d2);
            else if(i==0) ans+=dfs(tp^1,x-1,(d1*10+i)%Mod,d2);
            else if(i==cnt[x-1]) ans+=dfs(tp,x-1,(d1*10+i)%Mod,getd(d2,i));
            else ans+=dfs(tp^1,x-1,(d1*10+i)%Mod,getd(d2,i));
        }
        return ans;
    }
}
LL solve(LL x)
{
    if(x==0) return 0;
    LL d=x;tot=0;
    while(d!=0){cnt[++tot]=d%10;d/=10;}
    LL ans=0;
    for(int i=0;i<=cnt[tot];i++)
    {
        if(i==0) ans+=dfs(0,tot,0,0);
        else if(i==cnt[tot]) ans+=dfs(1,tot,i,i);
        else ans+=dfs(0,tot,i,i);
    }
    return ans;
}
int main()
{
    pre();
    int T;
    scanf("%d",&T);
    memset(f,-1,sizeof(f));
    while(T--)
    {
        LL l,r;
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",solve(r)-solve(l-1));
    }
    return 0;
}

 

posted @ 2018-10-30 10:20  Star_Feel  阅读(330)  评论(0编辑  收藏  举报