首页 > 其他 > 详细

[BZOJ3679]数字之积

时间:2018-11-06 19:05:22      阅读:170      评论:0      收藏:0      [点我收藏+]

[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;
}

[BZOJ3679]数字之积

原文:https://www.cnblogs.com/skylee03/p/9917064.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!