CodeForces - 55D A - Beautiful numbers

CodeForces - 55D A - Beautiful numbers(数位dp)

题目链接:https://cn.vjudge.net/contest/163023#problem/A
题目大意:求L~R范围内能被本身每个非零位整除的数的个数。(1 ≤ l ≤ r ≤ 9 ·1e18)
题目分析:
第一个要知道的知识点:
sum%(x*n)%x == sum%x;

证明:设sum = k*x+b
    等号左边:
        sum%(x*n)%x -> (k*x+b)%(x*n)%x 
        将k转为ka*n + kb代入;
        (ka*n*x+kb*x+b)%(x*n)%x -> (kb*x+b)%x -> b%x -> b
    等号右边:
        b
左右相等,证明成立  

因为我们数位dp是枚举的每一位,所以dfs枚举到当前位时要知道上一种状态的和,因为要算取模嘛。但是这个数据范围太大,当枚举9位之后的我们没办法开这么大的数组来记录。所以我们利用 sum%(x*n)%x == sum%x;这个来给它取模变小,这是n取2520是最合适的,以为它是1~9的最小公倍数。这就是为什么代码里面left要%2520。
第二个知识点:
就是怎样实现一个数能整除所有组成它的非0数字。 我们枚举到当前位的时候已经知道上一步的left了,我们用一个lcm来记录上个状态的最小公倍数,和这个状态的i求最小公倍数就是要传递下去的最小公倍数。但是这个最小公倍数最大能到是2520,我们不可能去开一个dp[19][2520][2520],所以要想办法变小。所以对lcm进行离散化,因为lcm一定可以整除2520,所以将1~2520可以整除2520的数进行标记即可,测试后发现只有48个,满足当前情况。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;

int data[20];
const int MOD = 2520;
ll dp[25][50][2550];
int Hash[2550];
//dp[pos][lcm][left]
//pos是当前位
//lcm是截止当前位的所有数的最小公倍数。
//left是截止当前位的数对2520取余后的值。

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b , a % b);
}

ll dfs(int pos, int left, int lcm, bool limit)
{
    if(pos == -1) return left % lcm == 0;

    if(!limit && ~dp[pos][Hash[lcm]][left]) return dp[pos][Hash[lcm]][left];

    int up = limit ? data[pos] : 9;
    ll ans = 0;

    for(int i = 0; i <= up; i++)
    {
        ans += dfs(pos - 1, (left * 10 + i) % MOD, i ? (lcm * i / gcd(lcm, i)) : lcm, i == data[pos] && limit);
    }

    if(!limit) dp[pos][Hash[lcm]][left] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[pos++] = n % 10;
        n /= 10;
    }
    return dfs(pos - 1, 0, 1, true);
}

int main()
{
    int t;
    ll a, b;
    int cnt = 0;
    scanf("%d", &t);
    for(int i = 1; i <= MOD; i++)
    {
        if(MOD % i == 0) Hash[i] = cnt++;
    }
    memset(dp, -1, sizeof(dp));
    while(t--)
    {
        scanf("%lld %lld", &a, &b);
        printf("%lld\n", solve(b) - solve(a - 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/79927075