[BZOJ3679]数字之积
[BZOJ3679]数字之积
题目大意:
定义\(f(x)\)为\(x\)各数位数字之积,求\([l,r)(l,r\le10^{18})\)中满足\(0<f(x)\le n(n\le10^9)\)的数的个数。
思路:
由于最终的乘积包含的质因子只可能有\(2,3,5,7\),因此最后乘积的数量十分有限。可以先使用一次DFS求出所有可能的乘积,然后再数位DP即可。
源代码:
#include<set>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
typedef long long int64;
inline int64 getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int64 x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
typedef long long int64;
const int S=5195;
const int p[]={2,3,5,7};
int n,d[19],v[S];
std::set<int> set;
void dfs(const int &x) {
if(set.count(x)) return;
set.insert(x);
for(register int i=0;i<4;i++) {
if(1ll*x*p[i]<=n) {
dfs(x*p[i]);
}
}
}
int64 f[19][S];
inline int find(const int &x) {
return std::lower_bound(&v[1],&v[v[0]]+1,x)-v;
}
inline int64 dp(const int &dep,const int &zero,const int &limit,const int &s) {
if(dep==0) return !zero;
if(!zero&&!limit&&f[dep][s]!=-1) return f[dep][s];
int64 ret=0;
const int lim=limit?d[dep]:9;
if(zero) {
ret+=dp(dep-1,true,false,1);
}
for(register int i=1;i<=lim;i++) {
if(1ll*v[s]*i>n) continue;
ret+=dp(dep-1,false,limit&&i==lim,find(v[s]*i));
}
if(!zero&&!limit) f[dep][s]=ret;
return ret;
}
inline int64 solve(int64 x) {
for(d[0]=0;x;x/=10) d[++d[0]]=x%10;
return dp(d[0],true,true,1);
}
int main() {
n=getint();
dfs(1);
for(register std::set<int>::iterator i=set.begin();i!=set.end();i++) {
v[++v[0]]=*i;
}
set.clear();
const int64 l=getint()-1,r=getint()-1;
memset(f,-1,sizeof f);
printf("%lld\n",solve(r)-solve(l));
return 0;
}