一个数x各个数位上的数之积记为f(x) <不含前导零>
求[L,R)中满足0<f(x)<=n的数的个数
求[L,R)中满足0<f(x)<=n的数的个数
还是老套路,这里加一维表示前POS位的数字乘积为sum.
然后就是注意前导0的问题,可以多开一位纪录前导0 ,也可以在记忆化的时候判断一下,感觉还是有很多细节没有想到。
还有一点就是:乘积要离散化,用map来离散化。
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<set>
#include<iostream>
using namespace std;
#define INF 0x7f7f7f7f
#define LL long long
LL dp[20][6000];
LL n;
int cnt,a[20];
map<LL,int> use;
LL dfs(int pos,LL chengji,bool lead,bool limit)
{
if(chengji>n)
return 0;
if(use[chengji]==0)
use[chengji]=cnt++;
if(pos==-1)
{
if(chengji>0&&chengji<=n)
return 1;
return 0;
}
if(lead&&!limit&&dp[pos][use[chengji]]!=-1)
return dp[pos][use[chengji]];
int up=limit ? a[pos]:9;
LL ret=0;
for(int i=0;i<=up;i++)
{
if(i==0)
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,0,false,limit&&i==a[pos]);
}
else
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,i,true,limit&&i==a[pos]);
}
}
if(!limit&&lead==1)
dp[pos][use[chengji]]=ret;
return ret;
}
LL solve(LL x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,false,true);
}
int main()
{
memset(dp,-1,sizeof(dp));
LL l,r;
use.clear();
cnt=1;
scanf("%lld",&n);
scanf("%lld%lld",&l,&r);
LL ans=solve(r-1)-solve(l-1);
printf("%lld\n",ans);
return 0;
}