[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;
}
posted @ 2018-11-06 18:26  skylee03  阅读(263)  评论(0编辑  收藏  举报