数位DP 2

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数位DP 2相关的知识,希望对你有一定的参考价值。

1.3679 数字之积

很套路的数位DP

关键在于预处理出所有可能的乘积,爆搜是9^18好像,反正几年跑出来(SXY大佬帮我算的这个)

根据唯一分解定理,因为所有数都是1~9,所以只要枚举2^a*3^b*5^c*7^d就可以预处理出来了。

技术分享
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
using namespace std;
typedef long long LL;
const int maxn=1e9;
LL tp,n,a[6000],dp[20][6000],sz,l,r,ansl,ansr;
int lim[20],cnt;
void pre(){
    for(int i=0;i<=30;i++)
      for(int j=0;j<=19;j++)
        for(int k=0;k<=13;k++)
          for(int l=0;l<=11;l++){
             LL res=pow(2,i)*pow(3,j)*pow(5,k)*pow(7,l);
             if(res>0&&res<=n) a[++sz]=res;
        }
    sort(a+1,a+sz+1);
} 
LL dfs(int pos,int sum,int limit,int flag){
    if(!pos) return 1;
    if(!limit&&~dp[pos][sum]) return dp[pos][sum];
    int up=limit?lim[pos]:9; 
    LL res=0;
    for(int i=(!flag||(flag&&pos==1));i<=up;i++){
        LL realsum=a[sum];
        if(flag) realsum=1;
        if(realsum*i>n) break;
        if(realsum*i<=n){
        int now=lower_bound(a,a+sz+1,realsum*i)-a;
        res+=dfs(pos-1,now,limit&&i==lim[pos],flag&&i==0);
        }
    }
    if(!limit) dp[pos][sum]=res;
    return res;
}
void cal(LL x,LL &ans){
    if(!x) {return;}
    memset(dp,-1,sizeof(dp));
    cnt=0; tp=x;
    while(tp) {lim[++cnt]=tp%10; tp/=10;}
    ans+=dfs(cnt,1,1,1);
}
int main()
{
    scanf("%lld%lld%lld",&n,&l,&r);
    pre(); 
    cal(l-1,ansl);
    cal(r-1,ansr);
    printf("%lld\n",ansr-ansl);
    return 0;
}
3679 数字之积

 

以上是关于数位DP 2的主要内容,如果未能解决你的问题,请参考以下文章

数位dp

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)

kotlin-从一个片段更改多个片段的小数位

数位DP练习

BZOJ1026 [SCOI2009]windy数 数位dp

BZOJ1026: [SCOI2009]windy数 ( 数位dp )