【CF55D】Beautiful numbers

跟風遠走 提交于 2019-12-02 02:51:41

【CF55D】Beautiful numbers

题面

洛谷

题解

考虑到如果一个数整除所有数那么可以整除他们的\(lcm\),而如果数\(x\)满足\(x\bmod Lcm(1,2...,9)=r\),且\(r\bmod Lcm\{x有的数\}=0\),那么这个数一定满足条件。

因为\(Lcm(1,2...,9)=2520\)比较小,所以我们可以存下来。

考虑数位dp,我们设\(f[i][lcm][r]\)表示目前\(dp\)到第\(i\)位,当前已选的数的\(lcm\)\(lcm\),前面几位\(\bmod 2520\)\(r\)的数的个数。

因为\(lcm\)实际上最多\(48\)个,那么我们将这\(48\)个数离散一下,\(dp\)数组的空间就开得下了,再按照普通数位\(dp\)的思路转移一下就可以了。

代码

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std;
const int Mod = 2520; 
long long L, R; 
int num[20], cnt, mp[2521], tot; 
int Lcm(int x, int y) { return y ? x * y / __gcd(x, y) : x; } 
long long f[20][50][2520]; 
long long Dp(int x, int lcm, int r, bool op) { 
    if (!x) return r % lcm ? 0 : 1; 
    if (!op && f[x][mp[lcm]][r] != -1) return f[x][mp[lcm]][r]; 
    int mx = op ? num[x] : 9; 
    long long res = 0; 
    for (int i = 0; i <= mx; i++) 
        res += Dp(x - 1, Lcm(lcm, i), (r * 10 + i) % Mod, op & (i == mx)); 
    if (!op) f[x][mp[lcm]][r] = res; 
    return res; 
} 
long long solve(long long pos) { 
    cnt = 0; 
    while (pos) num[++cnt] = pos % 10, pos /= 10; 
    num[cnt + 1] = 0; 
    return Dp(cnt + 1, 1, 0, 1); 
} 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif
    memset(f, -1, sizeof(f)); 
    for (int i = 1; i <= Mod; i++) if (Mod % i == 0) mp[i] = ++tot;
    int T; cin >> T; 
    while (T--) {
        cin >> L >> R;
        cout << solve(R) - solve(L - 1) << endl;
    } 
    return 0; 
} 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!