问有多少个没有前导 \(0\) 的 \(n\) 位数,存在一个不为 \(0\) 的后缀能被 \(k\) 整除,模 \(m\) .
\(1\leq n\leq 1000,1\leq k\leq 100,1\leq m\leq 10^9\)
数位 \(dp\) .
luogu 的题面翻译有大问题,漏掉了这个后缀不能为 \(0\) ,害得我看了一个晚上愣是没看出来.
想到状态 \(f(i,j,0/1)\) 表示从后往前第 \(i\) 位,后 \(i\) 位模 \(k\) 的余数是 \(j\) ,是否已经存在一个不为 \(0\) 的后缀的数的个数 .
转移的时候,枚举下一位填的数字,要注意判断当前后缀是否为 \(0\) 以及第一位是否为 \(0\) ( 即没有前导 \(0\) ) .
时间复杂度 : \(\mathrm O(10nk)\)
空间复杂度 : \(O(nk)\)
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
int res=0;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return res;
}
inline void print(int res){
if(res==0){
putchar('0');
return;
}
int a[10],len=0;
while(res>0){
a[len++]=res%10;
res/=10;
}
for(int i=len-1;i>=0;i--)
putchar(a[i]+'0');
}
int n,k,mod;
int p[1010];
int f[1010][110][2];
inline void upd(int &x,int y){x=(x+y)%mod;}
int main(){
n=read();k=read();mod=read();
p[0]=1;
for(int i=1;i<n;i++)p[i]=p[i-1]*10%k;
for(int i=(n==1);i<10;i++){
upd(f[0][i%k][((i%k)==0)&&(i!=0)],1);
}
for(int i=0;i+1<n;i++)for(int j=0;j<k;j++){
for(int d=((i+1)==(n-1));d<10;d++){
upd(f[i+1][(d*p[i+1]%k+j)%k][(((d*p[i+1]%k+j)%k)==0)&&(d!=0)],f[i][j][0]);
upd(f[i+1][(d*p[i+1]%k+j)%k][1],f[i][j][1]);
}
}
int ans=0;
for(int i=0;i<k;i++){
upd(ans,f[n-1][i][1]);
}
print(ans);
putchar('\n');
return 0;
}
/*inline? ll or int? size? min max?*/