P6371
题目描述
题解
分两种情况
1,
x
<
=
1
e
5
x<=1e5
x<=1e5,数位dp(注意前导零)
2,
x
>
1
e
5
x>1e5
x>1e5,因为
A
/
k
<
B
/
k
<
1
e
6
A/k<B/k<1e6
A/k<B/k<1e6,所以枚举
k
k
k的倍数,判断是否合法
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int dp[20][100002],a[100],n,m,k,bj[12];
char ss[2],s[12];
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int dfs(int pos,int val,bool limit,bool lead){
if(pos==-1) return val==0&&lead==0;
if(!limit&&!lead&&dp[pos][val]!=-1) return dp[pos][val];
int up=limit?a[pos]:9,ans=0;
for(int i=1;i<=up;i++)
if(bj[i]) ans+=dfs(pos-1,(val*10+i)%k,limit&&(i==a[pos]),lead&&(i==0));
if(lead) ans+=dfs(pos-1,0,limit&&(a[pos]==0),lead);
else if(bj[0]) ans+=dfs(pos-1,val*10%k,limit&&(a[pos]==0),lead);//关键,考虑前导零
if(!limit&&!lead) dp[pos][val]=ans;
return ans;
}
int solve(int x){
int tot=0;
while(x){
a[tot++]=x%10;
x/=10;
}return dfs(tot-1,0,1,1);
}
bool check(int x){
while(x){
if(!bj[x%10])return 0;
x/=10;
}return 1;
}
signed main(){
memset(dp,-1,sizeof(dp));
k=read(),n=read(),m=read();
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar());
for(;isdigit(ch);ch=getchar()) bj[ch-'0']=1;
if(k<100000)printf("%lld\n",solve(m)-solve(n-1));//1e5以下,数位dp
else{//1e5以上,枚举k的倍数,判断是否合法
int l=(int)((n-1)/k+1),r=(int)(m/k),ans=0;
for(int i=l;i<=r;i++)
if(check(1ll*k*i)) ans++;
printf("%lld\n",ans);
}return 0;
}