数位DP
知识要点
一般都比较有套路,主要是要考虑仔细,并且要和其他知识点结合
常用方法
就拿一道经典例题来说吧。
例:求区间[A,B]间恰有K个8的数的个数
cnt[L][K]表示长度为L且恰含K个8的数的个数 (包含前导0)
cnt[1][1]=1,cnt[1][0]=9;
如何计算[1-3981],K=1?
首位为1,2的数2*cnt[3][1]
前两位为30-38的数8*cnt[2][1]+1*cnt[2][0];
前三位为390-397的数8*cnt[1][1]
前四位为3981的数cnt[0][0];
首位为0的四位数cnt[3][1]
如何求cnt[L][K]?
cnt[0][0]=1;cnt[0][i]=0(i>0)
cnt[L][K]=cnt[L-1][K]*9+cnt[L-1][K-1];
例题
1. Poj3252
dp[ l ][ one ][ zero ][ flag ]
长度还剩l个 前面有one个1 zero个0 是否开始计数。
转移:直接枚举当前位取0还是1
2. Hdu 4734
dp[x][y]表示有x为,还剩下y的f值供选择,转移时枚举下一位即可
3. Codeforces 55D
dfs(len, num, lcm, flag)
len表示迭代的长度,
num为截止当前位的数对2520取余后的值。
lcm为截止当前位的所有数的最小公倍数。
flag表示当前数是否可以任意取值(对取值上限进行判断)
需要注意的是lcm按2520取值根本开不下,所以对lcm进行离散化,因为lcm一定可以整除2520,所以将1~2520可以整除2520的数进行标记即可,测试后发现只有48个满足。
4. 计蒜之道2017复赛
口胡题。。。莫比乌斯反演加按位统计
来自flx的正(口)解(胡)
假设在上一位,每个 j ( j ∈ [ 1, p − 1]) 有一个方案数 f 0[ j ]
那么这一次更新的时候相当于对于 i 要求一个新的方案
则f1[i]=∑j=1p−1[gcd(i,j)==1]×f0[j]