题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3679
解法: 比较裸的数位DP,dp[i][j][k]表示前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值),然后按照数位DP的做法去写就可以了。
///BZOJ 3679
///数位DP,离散化
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL dp[20][10][6000];
///dp[i][j][k]前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值)
LL l, r;
int digit[20];
int a[6000];
int n, tot, num;
map<LL,int>p;
///2,3,5,7
bool check(int a, int b, int c, int d){
long long ans=1;
for(int i=1; i<=a; i++) ans*=2;
if(ans>n) return 0;
for(int i=1; i<=b; i++) ans*=3;
if(ans>n) return 0;
for(int i=1; i<=c; i++) ans*=5;
if(ans>n) return 0;
for(int i=1; i<=d; i++) ans*=7;
if(ans>n) return 0;
return 1;
}
int cal(int a, int b, int c, int d){
int ans=1;
for(int i=1; i<=a; i++) ans*=2;
for(int i=1; i<=b; i++) ans*=3;
for(int i=1; i<=c; i++) ans*=5;
for(int i=1; i<=d; i++) ans*=7;
return ans;
}
long long f(LL x){
LL ans=0;
num=0;
while(x){
digit[++num]=x%10;
x/=10;
}
for(int i=1; i<=num/2; i++) swap(digit[i],digit[num-i+1]);
for(int i=1; i<num; i++)
for(int j=1; j<=9; j++)
for(int k=1; k<=tot; k++)
ans += dp[num-i][j][k];
LL sum=1;
for(int i=1; i<=num; i++){
for(int j=1; j<digit[i]; j++){
for(int k=1; k<=tot; k++){
if(a[k]*sum>n) break;
ans+=dp[num-i+1][j][k];
}
}
sum*=digit[i];
if(sum>n||sum==0) break;
}
return ans;
}
int main(){
scanf("%d", &n);
for(int i=0; i<=31; i++){
for(int j=0; j<=18; j++){
for(int k=0; k<=13; k++){
for(int l=0; l<=10; l++){
if(check(i,j,k,l)){
a[++tot]=cal(i,j,k,l);
}
}
}
}
}
sort(a+1,a+tot+1);
for(int i=1; i<=tot; i++) p[a[i]]=i;
scanf("%lld%lld",&l,&r);
for(int i=1; i<=9; i++) if(p[i]) dp[1][i][p[i]]=1;
for(int i=1; i<=18; i++){
for(int j=1; j<=9; j++){
for(int q=1; q<=tot; q++){
if(dp[i][j][q]){
for(int k=1; k<=9; k++){
if((long long)a[q]*k<=n && p[a[q]*k]) dp[i+1][k][p[a[q]*k]]+=dp[i][j][q];
}
}
}
}
}
long long ans = f(r)-f(l);
printf("%lld\n", ans);
return 0;
}
DFS版本:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
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==1&&!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)
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;
}