数字之积(数位dp+离散化)数字之积 HYSBZ - 3679

如何提高博客访问量?


数字之积题目链接
题意:一个数x各个数位上的数之积记为f(x) <不含前导零> 求[L,R)中满足0<f(x)<=n的数的个数
0<L<R<10^18 , n<=10^9
解题思路:如果打表的话就会发现f(x)只有4000多个…所以可以去离散化。当然,如果你是数学带佬,你也可以直接发现所有的素因子只有2,3,5,7,所以最后的 乘积只会有几千种(我不知道怎么算出来的qwq)。只要发现了这一点,这道题就变得比较简单了。构建dp[pos][mul] 去维护长度为pos时,乘积为mul的数量。
错误原因:

  1. 想不到f(x)可以离散化
  2. dp数组暴int了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=10007;
const int maxn=1e5+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
LL dp[20][maxn];
map<LL, int>lsh;
int num[30];
int cnt;
LL n;

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

LL dfs(int pos,LL mul,bool limit,bool lead){
    if (mul>n||(!lead&&mul==0)) return 0;
    if (pos==0) return (mul>0&&mul<=n);
    if (dp[pos][lsh[mul]]!=-1&&!limit) return dp[pos][lsh[mul]];
    LL ans=0;
    int up=limit?num[pos]:9;
    for (int i=0;i<=up;i++){
        ans+=dfs(pos-1,lead?i:i*mul,limit&&i==num[pos],lead&&i==0);
    }
    if (!limit) dp[pos][lsh[mul]]=ans;
    return ans;
}

LL solve(LL m){
    int pos=0;
    while (m){
        num[++pos]=m%10;
        m/=10;
    }
    return dfs(pos,0,true, true);
}

int main (){
    lsh.clear();
    cnt=0;
    LL a,b;
    scanf("%lld%lld%lld",&n,&a,&b);
    get_lsh(1);
    MT(dp,-1);
    printf("%lld\n",solve(b-1)-solve(a-1));
    return 0;
}

发布了41 篇原创文章 · 获赞 20 · 访问量 3020

猜你喜欢

转载自blog.csdn.net/weixin_43925900/article/details/103990991