数字之积 (数位dp)

一个数x各个数位上的数之积记为f(x) <不含前导零>
求[L,R)中满足0

Input

第一行一个数n
第二行两个数L、R

Output

一个数,即满足条件的数的个数

Sample Input

5 19 22

Sample Output

1

Hint

 

100%     0

//#include"bits/stdc++.h"
//#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
#define lson l, mid, node << 1
#define rson mid + 1, r, node << 1 | 1
const int INF  =  0x3f3f3f3f;
const int O    =  1e6;
const int mod  =  10007;
const int maxn =  1e4+5;
const double PI  =  acos(-1.0);
const double E   =  2.718281828459;

const int _ = 1;
const int __ = 2;
const int ___ = 3;

int cnt =0;
mapmp; // 离散所有乘积

LL l, r, n, dp[20][maxn]; // dp[pos][mul] 表示pos位,乘积已为mul,满足条件的个数
int a[20];

void init(LL x){
    if(mp[x] || x > n) return;
    mp[x] = cnt ++;
    for(int i=1; i<=9; i++) init(x * i);
}

LL dfs(int pos , LL mul, int lead, int flag){
    if(mul > n || (!lead && mul == 0)) return 0;
    // 1, 因为不考虑乘积为0的情况,所以 (mul>n) || (不存在前导零但是mul为0) 时可以直接返回
    
    if(pos == -1) return mul <= n && mul > 0;
    if(!flag && ~dp[pos][mp[mul]]) return dp[pos][mp[mul]]; // 2
    
    LL sum = 0;
    int up = flag ? a[pos] : 9;
    for(int i=0; i<=up; i++)
        sum += dfs(pos -1, lead ? i: mul * i, lead && i == 0, flag && i == a[pos]);
        //存在前导零时,就可以不管前面直接计算后面,不存在前导零时,就需要计算前面的乘积
    
    if(!flag) dp[pos][mp[mul]] = sum; // 3
    return sum;
    // 如果没有1处后部分的条件(不存在前导零但是mul为0), 2,3处都必须加一个条件 (!lead)
}


LL solve( LL x ){
    int k = 0;
    while(x) { a[k ++] = x % 10;  x /= 10; }
    return dfs(k-1, 0, 1, 1);
}

int main(){
    scanf("%lld%lld%lld", &n, &l, &r);
    init(1); MT(dp, -1);
    printf("%lld\n", solve(r-1) - solve(l -1));
    return 0;
}

 

你可能感兴趣的:(数位dp)