题意
一个数x各个数位上的数之积记为f(x) <不含前导零>
求[L,R)中满足(0<f(x)<=n)的数的个数
题解
(第一次独立做出来的数位dp)
虽然也是很简单,熟悉数位dp的套路就行了。
数位dp是不是只要写个爆搜然后加个记忆化就行了啊?
先写了的爆搜, (dfs(i, limit, x, lead))表示当前搜到第i位,是否受顶端限制为limit,前面的乘积为x,当前是否为前导0为lead。
然后加记忆化因为这个dp是求(dfs)函数的值,只需要保存几个自变量对应的因变量值就行了,但是x范围很大。
但是其实x能取的值很少,因为x包含的质因子只有10以内的,用map存状态就行了(其实是运气好,并没有分析x的范围)。
#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) >> 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read(){
char c; int num, f = 1;
while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
return f * num;
}
map<int, int>f[109][2][2];
int n, len, a[109];
char s[109];
int dfs(int i, int limit, int x, int lead) {
if(x > n || x <= 0) return 0;
if(f[i][limit][lead].count(x)) return f[i][limit][lead][x];
if(i == len + 1) return x <= n && lead == 0;
int up = (limit ? a[i] : 9), ans = 0;
if(lead) ans += dfs(i + 1, 0, x, 1);
for(int p = 1; p <= up; p++) {
ans += dfs(i + 1, limit && p == up, x * p, 0);
}
f[i][limit][lead][x] = ans;
return ans;
}
int query(int x) {
len = 0;
for(int i = 0; i < 109; i++)
for(int j = 0; j <= 1; j++)
for(int k = 0; k <= 1; k++)
f[i][j][k].clear();
while(x) {
a[++len] = x % 10;
x /= 10;
}
reverse(a + 1, a + 1 + len);
return dfs(1, 1, 1, 1);
}
signed main()
{
int ans = 0, l, r;
n = read();
l = read(); r = read();
printf("%lld
", query(r - 1) - query(l - 1));
return 0;
}
/*
dfs(i, x, z)表示前i位,是否顶到上限,积为z的方案数。
*/