动态规划入门到入土——提高之数位dp

学会了数位dp你能水的题就多了,我水了4绿7蓝2紫。
数位dp建议采用记忆化搜索形式(dp形式的我不会)。
我的先上
我们定义 dp_{i,j} 表示搜索到第 i 位上一位是 j 的满足条件的数字个数。
剩下的我们拿代码讲。
首先是简介的主函数

int main()
{
	cin>>l>>r;
	cout<<work(r)-work(l-1);//这里用到前缀和的思想,work(i)表示前i个数满足条件的个数
	return 0;
}

然后是 work 函数

int work(int x)
{
	memset(dp,-1,sizeof(dp));//初始全是-1
	n=0;
	while(x!=0)//拆位
	{
		v[++n]=x%10;
		x/=10;
	}
	return dfs(n,-2,1,1);//下面我们会说到,第一个参数是哪一位(因为拆位是倒序的所以这里也要倒序),第二个参数是上一个数是多少(-2是为了满足第一位一定满足条件),第三个参数是是否全是0,第四个参数是有没有数字上限(比如数字114514,在第一位有数字上限,只能枚举到1,在11450x的时候,这个x就没有限制了可以是0~9)。
}

最重要的记忆化搜索来了

int dfs(int now,int last,bool zero,bool limit)
{
	int s=0,p;
	if(!now) return 1;//边界
	if(!zero&&!limit&&dp[now][last]!=-1) return dp[now][last];//记忆化(要注意要满足不是全是0也没有数字上限)
	p=(limit?v[now]:9);//如果有上限就只能遍历到v[now]
	for(int i=0;i<=p;++i)
	if(abs(i-last)>=2)//要满足题目中的条件,和上一位要相差2及以上
	{
		if(zero&&!i) s+=dfs(now-1,-2,1,limit&(i==p));//(还是全是0的情况)
		else s+=dfs(now-1,i,0,limit&(i==p));//其他情况
		//这里limit&(i==p)的意思是之前没有位数限制或这次遍历没遍历到顶的情况,都没有位数限制
	}
	if(!zero&&!limit) dp[now][last]=s;//也是记忆化的核心部分
	return s;
}

下面推荐一下我做过的水题(刚刚的那题就不放了):
1 2 3 4 5 6 7 8 9 10 11 12

1 个赞