cf507d The Maths Lecture

问有多少个没有前导 \(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?*/
上一篇:linux + eclipse + cdt 报错undefined reference......好麻烦的,这位大牛给出的方法可行,特此MARK!!!!


下一篇:研究生课程——learning from data——overview