codeforces 55D 数位DP

codeforces 55D


题意:

[ l , r ] 给定区间[l,r],限制条件:

  • 0 该数能被任意数位上不为0的数整除

问区间内满足以上条件的数的个数。


题解:

1 9 l c m 2 8 首先将由1—9中若干数字的lcm的个数离散化为2^8。
d p [ p o s ] [ l c m ] [ n u m ] b p o s l c m dp[pos][lcm][num]b表示查找到第pos位,截止当前位的所有数的最小公倍数为lcm,
2520 1 9 l c m n u m 截止当前位的数对2520(1—9的lcm)取模后的值为num的合法数的个数。

  • d f s ( p o s 1 , i < 2 ? l c m : ( l c m ( 1 < < ( i 2 ) ) ) , ( n u m 10 + i ) dfs(pos-1, i < 2 ? lcm : (lcm|(1<<(i-2))), (num*10+i)%2520, limit && i == bit[pos])

#include <bits\stdc++.h>
using namespace std;
typedef long long ll;
int bit[20];
ll dp[20][1<<8][2520];

ll dfs(int pos, int lcm, int num, bool limit){
    if(pos == 0){
        for(int i = 2 ; i <= 9 ; i++){
            if(lcm&(1<<(i-2)) && num%i != 0){
                return 0;
            }
        }
        return 1;
    }
    if(!limit && dp[pos][lcm][num] != -1){
        return dp[pos][lcm][num];
    }
    int up = (limit ? bit[pos] : 9);
    ll res = 0;
    for(int i = 0 ; i <= up ; i++){
        res += dfs(pos-1, i < 2 ? lcm : (lcm|(1<<(i-2))), (num*10+i)%2520, limit && i == bit[pos]);
    }
    if(!limit){
        dp[pos][lcm][num] = res;
    }
    return res;
}

ll count(ll x){
    int len = 0;
    while(x){
        bit[++len] = x%10;
        x /= 10;
    }
    return dfs(len, 0, 0, true);
}

int main() {
    int t;
    memset(dp, -1, sizeof(dp));
    for(cin >> t ; t > 0 ; t--){
        ll l, r;
        cin >> l >> r;
        cout << count(r)-count(l-1) << endl;
    }
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/CSDN_PatrickStar/article/details/89843002