51nod 1232 完美数

Posted 声声醉如兰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1232 完美数相关的知识,希望对你有一定的参考价值。

题目思路:数位dp,若这个数能被每位的非0数整除,那么这个数一定可以被每一位数的lcm整除,lcm(1,2,3,4,5,6,7,8,9) = 2520,所以可以通过将这个数对2520取模来压缩空间,取模结果计做mod

dp[pos][lcm][mod],显然20*2520*2520仍然过大,所以我们对mod进行离散,再次压缩空间。

 

技术分享
#include <iostream>
#include <cmath>
#include <string.h>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long
#define MAXSIZE 2600
#define INF 0x3f3f3f3f

LL dp[20][50][MAXSIZE];
const LL Mod = 2520;

int bit[MAXSIZE],ha[MAXSIZE];

LL gcd(LL n,LL m)
{
    if(n%m == 0)
        return m;
    return gcd(m,n%m);
}

void Init()
{
    int pos = 1;
    for(int i=1;i<=Mod;i++)
    {
        if(2520%i == 0)
            ha[i] = pos++;
    }
}

LL dfs(int pos,int lcm,int mod,int limit)
{
    if(pos < 0)
    {
        if(mod%lcm == 0)
            return 1;
        return 0;
    }

    if(dp[pos][ha[lcm]][mod] != -1 && !limit)
        return dp[pos][ha[lcm]][mod];

    LL ans = 0;
    int len = limit?bit[pos]:9;
    for(int i=0;i<=len;i++)
    {
        if(i != 0)
        {
            int new_lcm = lcm*i/(gcd(lcm,i));
            int num = (mod*10+i)%Mod;
            ans += dfs(pos-1,new_lcm,num,limit&&i==len);
        }

        else
        {
            int num = mod*10%Mod;
            ans += dfs(pos-1,lcm,num,limit&&i==len);
        }
    }
    if(!limit)
        dp[pos][ha[lcm]][mod] = ans;
    return ans;
}

LL Solve(LL n)
{
    int pos = 0;
    while(n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    LL ans = dfs(pos-1,1,0,1);
    return ans;
}

int main()
{
    Init();
    int T;
    LL n,m;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        LL ans = Solve(m) - Solve(n-1);
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

以上是关于51nod 1232 完美数的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1232 完美数 数位dp

51nod 1232 完美数

51nod1780 完美序列

51nod 1623 完美消除(数位DP)

动态规划51nod1780 完美序列

51NOD 1182 完美字符串