YBTOJ区间圆数(数位DP)
这也是一道数位DP的模板题,这一次是记忆化搜索的写法。
变量说明:
- limit:当前位能否取到最大值(此题中的 1,10 进制中就是能否取到 9);
- lead:当前位是否是前导 0;
- pos:当前是从前向后的第 pos 位。
- cha:0 比 1 多多少。由于可能出现负数,统统加上了 30;
- vis(pos,cha),f(pos,cha):两个记忆化数组,记录没有限制且没有前导 0 时的情况是否搜索过,并记录搜索结果。
逐行解释:
- if(pos==0) return cha>=30;
如果当前所有位搜索完毕,0 比 1 多(差值大于 0)返回 1,否则返回 0。 - if(!limit&&!lead&&vis[pos][cha]) return f[pos][cha];
如果当前没有特殊限制并且已经搜索过了,直接返回。 - int up=limit?a[pos]:1;
当前位能去到的最大值。有限制那么就是原数中的 pospos 位,没有限制也只能取到 1. - res+=dfs(limit&(i== a[pos]), lead &(i== 0), pos-1,
cha+(i==0?(lead?0:1):-1));
如果之前都有限制且这一位也顶上了位,那么 limitlimit 也是1;如果之前都是前导 0 且这一位还是 0,那么这一位还是前导 0;位置就往下一位搜;计算新差值(前导 0 统统不算)。 - if(!limit&&!lead) vis[pos][cha]=1, f[pos][cha]=res;
当前不是特殊情况,那么就记忆下来。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int read()
{
int x=0,f=1;char ch=' ';
while(!isdigit(ch)) {
ch=