文章目录
-
- 数位DP 解题报告
-
- HDU 4722 Good Numbers
- HDU 2089 不要62
- HDU 3555 Bomb
- HDU 3652 B-number
- PKU 3252 Round Numbers
- HDU 4151 The Special Number
- PKU 3286 How many 0's?
- HDU 1663 The Counting Problem
- 洛谷 P2602 数字计数
- 洛谷 P2657 windy 数
- 洛谷 P3413 萌数
- 洛谷 P6754 Palindrome-Free Numbers
- 洛谷 P4317 花神的数论题
- HDU 5898 odd-even number
- HDU 4734 F(x)
- HDU 6148 Valley Numer
- HDU 5179 beautiful number
- 洛谷 P4124 手机号码
- 洛谷 CF855E Salazar Slytherin's Locket
- 洛谷 P6371 V
- 洛谷 P4127 同类分布
- HDU 5787 K-wolf Number
- PKU 3208 Apocalypse Someday
- HDU 5965 扫雷
- HDU 5456 Matches Puzzle Game
- HDU 3709 Balanced Number
- HDU 4507 吉哥系列故事——恨7不成妻
- HDU 4352 XHXJ's LIS
- 洛谷 CF55D Beautiful numbers
- HDU 5676 ztr loves lucky numbers
数位DP 解题报告
HDU 4722 Good Numbers
链接:HDU 4722 Good Numbers
题意:如果一个数的所有位数加起来是 10 10 10 的倍数, 则称之为 g o o d n u m b e r good \ number good number,求区间 [ l , r ] ( 0 ≤ l ≤ r ≤ 1 0 18 ) [l, r](0 \le l \le r \le 10^{18}) [l,r](0≤l≤r≤1018) 内 g o o d n u m b e r good \ number good number 的个数;
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题1】的讲解。
HDU 2089 不要62
链接:HDU 2089 不要62
题意:对于一个数字,如果出现 4 或者 62 ,则属于不吉利数字,给定 n , m ( 0 < n < m < 1 0 6 ) n, m(0 \lt n \lt m < 10^6) n,m(0<n<m<106),求 [ n , m ] [n, m] [n,m] 中非不吉利数字的个数。
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题2】的讲解。
HDU 3555 Bomb
链接:HDU 3555 Bomb
题意:给定一个 n ( 1 ≤ n ≤ 2 63 − 1 ) n(1 \le n \le 2^{63}-1) n(1≤n≤263−1),求小于等于 n n n 的数字中包含 49 的数的个数。
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题3】的讲解。
HDU 3652 B-number
链接:HDU 3652 B-number
题意:一个数的十进制包含子串 “13” 并且能被 13 整除,则被称为 B数,求小于等于 n ( n ≤ 1 0 9 ) n(n \le 10^9) n(n≤109) 的 B数。
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题4】的讲解。
PKU 3252 Round Numbers
链接:PKU 3252 Round Numbers
题意:如果一个数的二进制表示中 0 的个数大于等于 1,则称它为 r o u n d n u m b e r round \ number round number,给定一个区间 [ a , b ] [a,b] [a,b],求其中 r o u n d n u m b e r round \ number round number 的个数。
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题5】的讲解。
HDU 4151 The Special Number
链接:HDU 4151 The Special Number
题意:一个数字的十进制下的每个位都不同,则称为 S p e c i a l N u m b e r Special \ Number Special Number,求小于 n ( n < 1 0 8 ) n(n \lt 10^8) n(n<108) 的数的个数。
- 题解参考 夜深人静写算法(二十九)- 数位DP 中【例题6】的讲解。
PKU 3286 How many 0’s?
链接:PKU 3286 How many 0’s?
题意:统计区间 [ a , b ] [a, b] [a,b] 中的 0 的数量。
- 首先利用差分法,用 g ( x ) g(x) g(x) 表示 [ 0 , x ] [0, x] [0,x] 中 0 0 0 的数量,答案就是 g ( b ) − g ( a − 1 ) g(b) - g(a-1) g(b)−g(a−1)。
- 这个题可以说是没有任何显式的约束条件,但是我们在统计的时候需要注意一个很重要的点,就是前导零是不能纳入统计的。所以在定义前缀状态的时候,对于一个长度为 n n n 的数字,我们可以分为 3 类:
- 1)状态0: n n n 个 0 的情况;
- 2)状态1: k ( k ≤ n − 1 ) k (k \le n-1) k(k≤n−1) 个 0 的情况;
- 3)状态2:其它情况;
- 状态转移如图所示:
0-9
0,n=1
0,n<>1
1-9
0-9
0
1
2
- 对于一个数 x x x,如果前缀状态处于 状态0,那么很显然,这个值就是零,所以零的个数为1;如果处于 状态1,那么到目前为止都是前导零,不应该纳入统计;如果处于 状态2,假设第 k k k 位的零出现次数为 h ( k ) h(k) h(k), 则有:
- h ( k ) = { 1 0 k − 1 l i m = t r u e x m o d 1 0 k − 1 + 1 l i m = f a l s e h(k) = \begin{cases} 10^{k-1} & lim = true \\ x \mod 10^{k-1} + 1 & lim = false \end{cases} h(k)={ 10k−1xmod10k−1+1lim=truelim=false
- 利用 数位DP 进行状态转移即可。
HDU 1663 The Counting Problem
链接:HDU 1663 The Counting Problem
题意:统计区间 [ a , b ] ( 0 < a , b < 1 0 8 ) [a, b](0 \lt a, b \lt 10^8) [a,b](0<a,b<108) 中每个数字的 [ 0 , 9 ] [0, 9] [0,9] 的数量。
洛谷 P2602 数字计数
链接:洛谷 P2602 数字计数
题意:统计区间 [ a , b ] ( 0 < a , b < 1 0 12 ) [a, b](0 \lt a, b \lt 10^{12}) [a,b](0<a,b<1012) 中每个数字的 [ 0 , 9 ] [0, 9] [0,9] 的数量。
- 同 HDU 1663 The Counting Problem
洛谷 P2657 windy 数
链接:洛谷 P2657 windy 数
题意:一个数字各个相邻位之差的绝对值不小于2则称为 Windy 数,统计区间 [ a , b ] ( 0 < a , b < 1 0 9 ) [a, b](0 \lt a, b \lt 10^9) [a,b](0<a,b<109) 中的 Windy 数 个数。
- 前缀状态定义:已经枚举的数字的前缀的最后一位;
- 状态转移:令前一位为 x x x,当前位为 y y y,状态转移发生在 ∣ x − y ∣ ≥ 2 |x - y| \ge 2 ∣x−y∣≥2 时;
- 前导零状态:前导零状态应该和任意状态都能发生状态转移,即满足 ∣ x − y ∣ ≥ 2 |x - y| \ge 2 ∣x−y∣≥2,所以可以用 11 进行编码。
洛谷 P3413 萌数
链接:洛谷 P3413 萌数
题意:如果一个数包含长度至少为2的回文串,则称为萌数,求区间 [ l , r ] ( l ≤ r ≤ 1 0 1000 ) [l, r](l \le r \le 10^{1000}) [l,r](l≤r≤101000) 内萌数的个数模 ( 1 0 9 + 7 10^9+7 109+7)。
- 前缀状态定义:已经枚举的数字的前缀的最后两位;不足两位的用 10 (前导零状态) 来补齐,一旦出现满足条件的回文串,则将状态变为饱和状态,用 11 编码,除了这两个特殊状态,用高位和低位来分别表示最后第二位 和 最后第一位。所以状态定义为:
[10] 表示前导零状态
[11] 表示饱和状态
[10][0-9] 表示一位数字
[0-9][0-9] 表示两位以上数字的最后两位
const int saturatedstate = 11;
const int leadingzerostate = 10;
bool isEndStateValid(stType state) {
return state == saturatedstate;
}
stType nextState(stType st, int digit) {
if(st == leadingzerostate) {
if(digit == 0) {
return leadingzerostate;
}
st = leadingzerostate * 100 + leadingzerostate;
}else if(st == saturatedstate) {
return saturatedstate;
}
int high = st/100, low = st%100;
if(high == digit || low == digit) {
return saturatedstate;
}
return low * 100 + digit;
}
洛谷 P6754 Palindrome-Free Numbers
链接:洛谷 P6754 Palindrome-Free Numbers
同 洛谷 P3413 萌数
洛谷 P4317 花神的数论题
链接:洛谷 P4317 花神的数论题
题意:令 s u m ( i ) sum(i) sum(i) 表示 i i i 的二进制表示中 1 1 1 的个数。给出一个正整数 n ( n ≤ 1 0 15 ) n(n \le 10^{15}) n(n≤1015),求 ∏ i = 1 n s u m ( i ) m o d 10000007 \prod_{i=1}^{n} sum(i) \mod 10000007 ∏i=1nsum(i)mod10000007。
- 可以利用数位DP求出二进制表示中 1 的个数为 k k k 个的,令其个数为 h ( k ) h(k) h(k)。
- 则最后的答案就是:
- ∏ k = 1 63 k h ( k ) m o d 10000007 \prod_{k=1}^{63}k^{h(k)} \mod 10000007 k=1∏63kh(k)mod10000007
- 利用二分快速幂求解最终答案。
- 由于是求 1 的个数所以不需要考虑前导零,如果是求0的个数就要引入前导零状态了。
HDU 5898 odd-even number
链接:HDU 5898 odd-even number
题意:如果一个数的连续奇数位有偶数个,连续偶数位有奇数个,则称为 o d d − e v e n n u m b e r odd-even \ number odd−even number,给定区间 [ l , r ] ( l ≤ r ≤ 1 0 18 ) [l, r](l \le r \le 10^{18}) [l,r](l≤r≤1018),求区间内 o d d − e v e n n u m b e r odd-even \ number odd−even number 的个数。
- 前缀状态定义:前缀的最后一位数字的奇偶性,以及连续相同奇偶性的数个数的奇偶性;高位代表枚举的数字的最后一位的奇偶性,低位代表连续相同奇偶性的数个数的奇偶性。所以状态定义为:
[12] 表示前导零状态
[0][1] 表示前缀最后这位为偶数,出现奇数次
[0][0] 表示前缀最后这位为偶数,出现偶数次
[1][0] 表示前缀最后这位为奇数,出现偶数次
[1][1] 表示前缀最后这位为奇数,出现奇数次
const int invalidstate = -123456789;
const int leadingzerostate = 12;
bool isEndStateValid(stType state) {
return state/10 != state%10;
}
stType nextState(stType st, int digit) {
if(st == leadingzerostate) {
if(digit == 0) {
return leadingzerostate;
}
return (digit&1) * 10 + 1;
}
int high = st/10, low = st%10;
int oddeven = (digit&1);
if(high != oddeven) {
if(high == low) {
return invalidstate;
}
return oddeven * 10 + 1;
}else {
return high*10 + (low^1);
}
}
HDU 4734 F(x)
链接:HDU 4734 F(x)
题意: x x x 表示为 10进制的 n n n 位数为 A n A n − 1 A n − 2 . . . A 2 A 1 A_nA_{n-1}A_{n-2} ... A_2A_1 AnAn−1An−2...A2A1, 定义 F ( x ) = A n ∗ 2 n − 1 + A n − 1 ∗ 2 n − 2 + . . . + A 2 ∗ 2 + A 1 ∗ 1 F(x) = A_n * 2^{n-1} + A_{n-1} * 2^{n-2} + ... + A_2 * 2 + A_1 * 1 F(x)=An∗2n−1+An−1∗2n−2+...+A2∗2+A1∗1给定两个数 A A A 和 B B B ( 0 ≤ A , B ≤ 1 0 9 ) (0 \le A,B \le 10^9) (0≤A,B≤109),求区间 [ 0 , B ] [0, B] [0,B] 中有多少数满足 F ( x ) ≤ F ( A ) F(x) \le F(A) F(x)≤F(A)。
- 由于 B B B 的范围限制,所以 F ( x ) F(x) F(x) 的最大值为 9 ∗ 2 8 + 9 ∗ 2 7 + . . . + 9 ∗ 2 0 = 9 ∗ ( 2 9 − 1 ) = 4599 9*2^8 + 9*2^7 + ... + 9*2^0 = 9 * (2^9 - 1) = 4599 9∗28+9∗27+...+9∗20=9∗(29−1)=4599。利用 F ( x ) F(x) F(x) 作为前缀状态 s t st st,定义状态 f ( n , s t , l i m ) f(n, st, lim) f(n,st,lim) 进行数位 DP。
- 这题需要注意,由于是海量数据,所以对于记忆化数组 f [ n ] [ s t ] f[n][st] f[n][st] 只能初始化一次。
- 并且需要加入一定的剪枝,比如当枚举到的某个数, l i m = t r u e lim = true lim=true 时,计算出的最大的 F ( x ) F(x) F(x) 都是小于等于 F ( a ) F(a) F(a) 的,那么答案就是 1 0 n 10^n 10n,不必再递归往下计算,直接返回即可。
HDU 6148 Valley Numer
链接:HDU 6148 Valley Numer
题意:如果一个数中出现县递增再递减的山峰,则为不合法数,求 [ 1 , n ] ( n ≤ 1 0 100 ) [1,n](n \le 10^{100}) [1,n](n≤10100) 中有多少合法数模(1000000007)。
第一位:
0 前导零状态
1 尚未出现过递增
2 出现过递增
第二位:
0-9 前缀的最后一位数字
HDU 5179 beautiful number
链接:HDU 5179 beautiful number
题意:对于一个数 A = ∑ i = 1 n a i ∗ 1 0 n − i ( 1 ≤ a i ≤ 9 ) A = \sum_{i=1}^{n} a_i∗10^{n−i}(1≤ai≤9) A=∑i=1nai∗10n−i(1≤ai≤9) 当满足以下两个条件时,我们称 A 为 “ b e a u t i f u l n u m b e r beautiful \ number beautiful number”
1) a i ≥ a i + 1 a_i \ge a_{i+1} ai≥ai+1;
2) a i m o d a j = 0 a_i \mod a_j = 0 aimodaj=0, 1 ≤ i ≤ n , i < j ≤ n 1 \le i \le n, i \lt j \le n 1≤i≤n,i<j≤n
现在给定区间 [ l , r ] ( l ≤ r ≤ 1 0 9 ) [l, r](l \le r \le 10^9) [l,r](l≤r≤109),求区间中 b e a u t i f u l n u m b e r beautiful \ number beautiful number 的数量。
- 前缀状态用二进制压缩,如果一个数字出现过,则在对应二进制比特位置1,数字总共9个,所以状态总数不会超过1023,再加上前导零状态,总共 1024 个状态。
- 状态转移就简单了,直接枚举对应位是否存在 1,有的话就进行整除合法性判断。
洛谷 P4124 手机号码
链接:洛谷 P4124 手机号码
题意:一个手机号需要同时满足以下三个条件:
1)不含前导零;
2)至少有三个相同的相邻数字;
3)4 和 8 不能同时出现;
给定一个区间 [ l , r ] [l, r] [l,r],求满足条件的手机号的个数。
- 三个条件分别做如下处理:
- 1)最高位必须从 1 开始枚举,才能保证不出现前导零;
- 2)状态位 [a][b],其中 [a] 表示前缀最后一个字符是 a a a,[b] 表示 a a a 出现的次数;
- 3)状态位 [c],c 的取值为 0(表示4和8都没出现),1(4出现了),2(8出现了);
- 状态转移利用数位 DP 求解即可。
洛谷 CF855E Salazar Slytherin’s Locket
链接:洛谷 CF855E Salazar Slytherin’s Locket
题意:求 [ l , r ] ( 1 ≤ l ≤ r ≤ 1 0 18 ) [l, r](1 \le l \le r \le 10^{18}) [l,r](1≤l≤r≤1018)区间中的数,转换成 b ( b ≤ 10 ) b(b \le 10) b(b≤10) 进制后, 0 , 1 , 2... , b − 2 , b − 1 0,1,2...,b-2,b-1 0,1,2...,b−2,b−1 都出现偶数次的数的个数。
- 每个数字出现 偶数次 或者 奇数次 可以用 0 或者 1 来表示,由于 b b b 的范围最大为 10,所以最多 2 10 2^{10} 210 个状态,再加上一个前导零状态,用 2048 表示。
- 然后就是套用 数位 DP 模板了。
洛谷 P6371 V
链接:洛谷 P6371 V
题意:使用给定的数字,组成一些在 [ l , r ] ( l ≤ r ≤ 1 0 11 ) [l,r](l \le r \le 10^{11}) [l,r](l≤r≤1011) 之间的数使得这些数每个都能被 X ( X ≤ 1 0 11 ) X(X \le 10^{11}) X(X≤1011) 整除。
- 分情况讨论:
- 1)当 X ≤ 1 0 5 X \le 10^5 X≤105,利用 数位 DP 求解,前缀状态就是存每个数前缀模 X X X 的值;
- 2)否则,直接暴力枚举 X X X 的倍数判可行性;
洛谷 P4127 同类分布
链接:洛谷 P4127 同类分布
题意:给出一个闭区间 [ l , r ] [l,r] [l,r],求各位数字之和能整除原数的数的个数。
- 两个前缀状态:
- 所有数字的和最大值为:9 * 长度 = 9 ∗ 19 < 180 = 9 * 19 < 180 =9∗19<180,所以可以枚举所有可能情况的和 s u m sum sum。
- 1)个位数字之和 n o w s u m nowsum nowsum;
- 2)原数模上 s u m sum sum 的余数 n o w m o d nowmod nowmod;
- 然后用 数位DP 进行状态转移,得到最终状态: ( n o w s u m , n o w m o d ) (nowsum,nowmod) (nowsum,nowmod) ,只有当 n o w s u m = s u m nowsum = sum nowsum=sum 且 n o w m o d = 0 nowmod = 0 nowmod=0 才是满足条件:各位数字之和为 s u m sum sum,且 s u m sum sum 能被原数整除的情况。
HDU 5787 K-wolf Number
链接:HDU 5787 K-wolf Number
题意:给出区间 [ l , r ] ( 1 ≤ l ≤ r ≤ 1 0 18 ) [l, r](1 \le l \le r \le 10^{18}) [l,r](1≤l≤r≤1018) 和 K ( 2 ≤ K ≤ 5 ) K(2 \le K \le 5) K(2≤K≤5),求区间中,十进制表示相邻 K K K 位都不同的数的个数。
- 用 11 11 11 进制来表示状态,其中 [ 0 , 9 ] [0,9] [0,9] 代表数字, 10 10 10 代表前导零,每次状态转移的时候检查前缀状态的 [ 0 , K ) [0, K) [0,K) 是否有当前枚举的这一位数字,如果有则不进行状态转移,否则把当前那一位附加到前缀状态末尾,每次只存 K K K 位状态,不过不足 K K K 位,用 10 10 10 补齐在最前面(前导零的情况)。
PKU 3208 Apocalypse Someday
链接:PKU 3208 Apocalypse Someday
题意:一个数如果至少包含 3 个 6,则称为 “beast number”,给定一个 k k k, 求第 k k k 个 “beast number”。
- 状态编码如下:
- 状态0:前缀数字最后位不是6,且未出现过连续3个6;
- 状态1:前缀数字最后位连续6的个数为1个,且未出现过连续3个6;
- 状态2:前缀数字最后位连续6的个数为2个,且未出现过连续3个6;
- 状态3:已经出现过连续3个6,饱和状态;
- 状态转移如下:
6
else
6
else
6
else
all
0
1
2
3
HDU 5965 扫雷
链接:HDU 5965 扫雷
题意:对于一个 3 × n ( n ≤ 10000 ) 3 \times n(n \le 10000) 3×n(n≤10000) 的格子上,中间一行均无地雷,显示了周围 8 个格子共有多少地雷,求一共有多少种方案。
- 用 f [ n ] [ 2 ] [ 2 ] [ 2 ] [ 2 ] f[n][2][2][2][2] f[n][2][2][2][2] 来表示状态,进行状态转移。
HDU 5456 Matches Puzzle Game
链接:HDU 5456 Matches Puzzle Game
题意:给出 n ( n ≤ 500 ) n(n \le 500) n(n≤500) 根火柴,然后给出如下火柴的样式,求满足条件的等式 A − B = C A - B = C A−B=C 的方案数,求方案数模 1 0 9 + 7 10^9+7 109+7。
如下图为火柴数为 ( n = 17 = 6 + 1 + 5 + 2 + 3 ) (n = 17 = 6 + 1 + 5 + 2 + 3) (n=17=6+1+5+2+3) 的其中一种方案。
- 首先预处理每个数字需要多少根火柴,存储在 num 数组中;
- 然后把等式转换成 A = B + C A = B + C A=B+C;
- 接着就是确定枚举方式,我们可以枚举 B 和 C 的每一位,相加的时候需要对齐,所以从低位到高位进行枚举,然后记录是否产生进位,从而确定 A 的对应位是什么,还要考虑前导零;
- 所以可以这么设计状态:
- f [ n ] [ 2 ] [ 2 ] [ 2 ] f[n][2][2][2] f[n][2][2][2],状态表示四维 f [ i ] [ j ] [ k ] [ l ] f[i][j][k][l] f[i][j][k][l]:
- 1) i i i 表示目前还有 i i i 根火柴的情况;
- 2) j j j 表示当前 B 这个数字是否已经枚举完;
- 3) k k k 表示当前 C 这个数字是否枚举完;
- 4) l l l 表示低位过来的进位是多少;
- 然后根据 j j j 和 k k k 是否枚举完进行分情况讨论,记忆化搜索即可。
HDU 3709 Balanced Number
链接:HDU 3709 Balanced Number
题意:如果一个数字满足以某个点为平衡点,两边数字的力矩相等,则称这个数为 “Balanced Number”,给定一个区间 [ a , b ] [a, b] [a,b],求区间中有多少 “Balanced Number”。例如:4139 就是一个 “Balanced Number”,因为它满足 4 ∗ 2 + 1 ∗ 1 = 9 ∗ 1 4*2 + 1*1 = 9*1 4∗2+1∗1=9∗1
- 首先,如果一个数 x x x,长度为 n n n,平衡点的位置在 p p p,那么把这个数字表示成十进制如下:
- x n x n − 1 . . . x p + 1 x p x p − 1 . . . x 2 x 1 x_nx_{n-1}...x_{p+1}x_px_{p-1}...x_2x_1 xnxn−1...xp+1xpxp−1...x2x1
- 那么,左边数字的力矩就是:
- l p = x n ∗ ( n − p ) + x n − 1 ∗ ( n − p − 1 ) + . . . + x p + 1 l_p = x_n*(n-p) + x_{n-1}*(n-p-1) + ... + x_{p+1} lp=xn∗(n−p)+xn−1∗(n−p−1)+...+xp+1
- 右边数字的力矩就是:
- r p = x p − 1 + . . . + x 2 ∗ ( p − 2 ) + x 1 ∗ ( p − 1 ) r_p = x_{p-1} + ... + x_2*(p-2) + x_1*(p-1) rp=xp−1+...+x2∗(p−2)+x1∗(p−1)
- 由于 p p p 是平衡点,那么 l p = r p l_p = r_p lp=rp。
- 那么,如果在 p p p 是平衡点的基础上,我们来看看是否有可能, p − 1 p-1 p−1 这个位置也是平衡点?
- 假设 p − 1 p-1 p−1 是平衡点,那么有:
- l p − 1 = x n ∗ ( n − p + 1 ) + x n − 1 ∗ ( n − p ) + . . . + x p = x n ∗ ( n − p ) + x n − 1 ∗ ( n − p − 1 ) + . . . + x p + 1 + ( x n + x n − 1 + . . . x p ) = l p + ∑ k = p n x k \begin{aligned}l_{p-1} &= x_n*(n-p+1) + x_{n-1}*(n-p) + ... + x_{p} \\ &= x_n*(n-p) + x_{n-1}*(n-p-1) + ... + x_{p+1} + (x_n+x_{n-1}+...x_{p}) \\ &= l_p + \sum_{k=p}^n x_{k}\end{aligned} lp−1=xn∗(n−p+1)+xn−1∗(n−p)+...+xp=xn∗(n−p)+xn−1∗(n−p−1)+...+xp+1+(xn+xn−1+...xp)=lp+k=p∑nxk
- r p − 1 = x p − 2 + . . . + x 2 ∗ ( p − 3 ) + x 1 ∗ ( p − 2 ) = x p − 1 + . . . + x 2 ∗ ( p − 2 ) + x 1 ∗ ( p − 1 ) − x p − 1 − . . . − x 2 − x 1 = r p − ∑ k = 1 p − 1 x k \begin{aligned}r_{p-1} &= x_{p-2} + ... + x_2*(p-3) + x_1*(p-2) \\ &= x_{p-1} + ... + x_2*(p-2) + x_1*(p-1) - x_{p-1} - ... - x_2 - x_1 \\ &= r_p - \sum_{k=1}^{p-1} x_{k} \end{aligned} rp−1=xp−2+...+x2∗(p−3)+x1∗(p−2)=xp−1+...+x2∗(p−2)+x1∗(p−1)−xp−1−...−x2−x1=rp−k=1∑p−1xk
- 满足等式: l p − 1 = r p − 1 l_{p-1} = r_{p-1} lp−1=rp−1
- 则需要满足 ∑ k = p n x k = − ∑ k = 1 p − 1 x k \sum_{k=p}^n x_{k} = - \sum_{k=1}^{p-1} x_{k} k=p∑nxk=−k=1∑p−1xk
- 除非 x k = 0 x_k = 0 xk=0,这种情况特殊处理,其他情况不可能满足有多个平衡点,所以可以求出所有以 p ( 1 ≤ p ≤ n ) p(1 \le p \le n) p(1≤p≤n) 为平衡点数字的和,就是整个问题的解了。
HDU 4507 吉哥系列故事——恨7不成妻
链接:HDU 4507 吉哥系列故事——恨7不成妻
题意:如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
给定一个区间 [ a , b ] [a, b] [a,b],求区间内和 7 无关的数字的平方和 模 1 0 9 + 7 10^9+7 109+7。
- 定义状态的时候可以这么考虑:
- 1)遇到 7 无法进行状态转移;
- 2)每位加起来的和 模 7 的余数作为 state1,范围 [ 0 , 6 ] [0, 6] [0,6];
- 3)枚举到当前前缀的和 模 7 的余数作为 state2,范围 [ 0 , 6 ] [0, 6] [0,6];
- 4)如果一个数 v v v 的最高位为 i i i,后面的位用未知数 x x x 表示,即 v = i ∗ 1 0 n + x v = i * 10^n + x v=i∗10n+x,那么 v 2 = i 2 ∗ 10 0 n + x 2 + 2 x i ∗ 1 0 n v^2 = i^2*100^n + x^2 + 2xi * 10^n v2=i2∗100n+x2+2xi∗10n
- ∑ v 2 = ∑ ( i 2 ∗ 10 0 n + x 2 + 2 x i ∗ 1 0 n ) = i 2 ∗ ∑ 10 0 n + ∑ x 2 + 2 i ∗ 1 0 n ∑ x \begin{aligned} \sum v^2 &= \sum (i^2*100^n + x^2 + 2xi * 10^n)\\ &= i^2 * \sum 100^n + \sum x^2 + 2i * 10^n \sum x\end{aligned} ∑v2=∑(i2∗100n+x2+2xi∗10n)=i2∗∑100n+∑x2+2i∗10n∑x
- 所以当最高位确定为 i i i 的时候,需要知道三个值:
- 1) x x x 取值有多少种?用 a a a 表示,则 i 2 ∗ ∑ 10 0 n = i 2 ∗ a ∗ 10 0 n i^2 * \sum 100^n = i^2 * a * 100^n i2∗∑100n=i2∗a∗100n
- 2) x x x 所有 x 求和为多少?用 b b b 表示,则 2 i ∗ 1 0 n ∑ x = 2 i ∗ 1 0 n b 2i * 10^n \sum x = 2i * 10^n b 2i∗10n∑x=2i∗10nb
- 3) x x x 所有 x 的平方和为多少?用 c c c 表示,则 ∑ x 2 = c \sum x^2 = c ∑x2=c
- 于是得到:
- ∑ v 2 = i 2 ∗ a ∗ 1 0 2 n + 2 i ∗ 1 0 n b + c \sum v^2 = i^2 * a * 10^{2n} + 2i * 10^n b + c ∑v2=i2∗a∗102n+2i∗10nb+c
- 而 a , b , c a, b, c a,b,c 又可以通过递归求得。
HDU 4352 XHXJ’s LIS
链接:HDU 4352 XHXJ’s LIS
题意:给定一个区间 [ L , R ] ( 0 < L ≤ R < 2 63 − 1 ) [L, R] ( 0 \lt L\le R \lt 2^{63}-1) [L,R](0<L≤R<263−1),和一个数 K ( K ≤ 10 ) K( K \le 10) K(K≤10),求区间中的数字表示成字符串后,最长严格递增子序列的长度为 K K K 的数字的数量。
- 建议先看下 夜深人静写算法(二十)- 最长单调子序列 其中提到的 n l o g 2 n nlog_2n nlog2n 的那个算法。
- 状态表示为:令 g i g_i gi 表示长度 i i i 为 的 递增子序列的最后一个数(即子序列中的第 i i i 个数)的最小值。
- 最大长度为 10,并且要求递增,所以这样的序列不会很多,我们可以用 d p dp dp 计数来求出这些序列共有多少种,列表如下:
d p [ i ] [ j ] dp[i][j] dp[i][j] |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
total |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
10 |
2 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
45 |
3 |
0 |
0 |
1 |
3 |
6 |
10 |
15 |
21 |
28 |
36 |
120 |
4 |
0 |
0 |
0 |
1 |
4 |
10 |
20 |
35 |
56 |
84 |
210 |
5 |
0 |
0 |
0 |
0 |
1 |
5 |
15 |
35 |
70 |
126 |
252 |
6 |
0 |
0 |
0 |
0 |
0 |
1 |
6 |
21 |
56 |
126 |
210 |
7 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
7 |
28 |
84 |
120 |
8 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
8 |
36 |
45 |
9 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
9 |
10 |
10 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
- 这张表表示的是 d p [ i ] [ j ] dp[i][j] dp[i][j],即 长度为 i i i 且以数字 j j j 结尾的递增序列的个数,我们看到,长度为 5 的情况下达到最大值,也就 252 个。所以对于每个序列都可以单独作为一个状态,即 12489、24567、56789 均为长度为 5 的合法状态,都是算在 252 个里面的;相反的, 87134 则不是合法状态。
- 由于数字很大,无法直接放到状态数组中,那么我们可以通过预处理,先把这些合法状态都预处理出来,然后存放到一个数组中,再通过二分去找到这个数字,返回下标来作为状态数组的下标。
- f [ n ] [ l e n ] [ s t a t e ] [ 2 ] [ 2 ] f[n][len][state][2][2] f[n][len][state][2][2] 来表示状态,数字本身的长度为 n n n,递增序列的最大长度 l e n len len,其中递增序列的状态 s t a t e state state,第一个 2 2 2 代表是否已经有非零的数字, 第二个 2 代表每一位的 limit,然后就可以进行数位DP了。
洛谷 CF55D Beautiful numbers
链接:洛谷 CF55D Beautiful numbers
题意:一个数字如果能够被它所有的非零位整除,则称之为: B e a u t i f u l n u m b e r Beautiful \ number Beautiful number,给定一个区间 [ l , r ] ( l ≤ r ≤ 9 ∗ 1 0 18 ) [l, r](l \le r \le 9*10^{18}) [l,r](l≤r≤9∗1018)
- 这道题比较巧妙,我们可以发现如下几个思考点:
- 1)首先考虑,如果一个数能被所有 [ 1 , 9 ] [1,9] [1,9] 的数字整除,那么就是被它们的最小公倍数整除,即 2520;
- 2)如果这个数字不包含所有 [ 1 , 9 ] [1,9] [1,9] 的数字,那么它们的最小公倍数一定比 2520 小,也一定是 2520 的因子;
- 3)假设原数为 x x x,模 2520 的值为 y = x m o d 2520 y = x \mod 2520 y=xmod2520,假设 t t t 为 2520 的因子,且是某些数字位的最小公倍数,那么有:
- x m o d t = y m o d t x \mod t = y \mod t xmodt=ymodt
- 根据以上几点,我们可以设计数位DP的状态为: f [ n ] [ l ] [ m o d ] ( n ≤ 20 , l ≤ 48 , m o d ≤ 2520 ) f[n][l][mod] (n \le 20, l \le 48, mod \le 2520) f[n][l][mod](n≤20,l≤48,mod≤2520)
- n n n 代表数位 DP 的长度, l l l 代表各种数字组合下的最小公倍数,总共 48 个; m o d mod mod 代表原数模 2520 的余数;
- 然后进行数位 DP 即可。
HDU 5676 ztr loves lucky numbers
链接:HDU 5676 ztr loves lucky numbers
题意:如果一个数只包含 4 和 7,则称为 幸运数,如果 4 和 7的个数相等,则称为超级幸运数。给定 n ( n ≤ 1 0 18 ) n(n \le 10^{18}) n(n≤1018),求 ≥ n \ge n ≥n 的最小超级幸运数。
- 不用 数位 DP 也可以做,直接枚举所有答案(不到 70000 个),然后二分找。