数位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; }
以上是关于数位DP 2的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)