解题报告 (十四) 数位DP

文章目录

    • 数位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](0lr1018) 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(1n2631),求小于等于 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(n109) 的 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(a1)
  • 这个题可以说是没有任何显式的约束条件,但是我们在统计的时候需要注意一个很重要的点,就是前导零是不能纳入统计的。所以在定义前缀状态的时候,对于一个长度为 n n n 的数字,我们可以分为 3 类:
  • 1)状态0: n n n 个 0 的情况;
  • 2)状态1: k ( k ≤ n − 1 ) k (k \le n-1) k(kn1) 个 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)={ 10k1xmod10k1+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] 的数量。

  • 同 PKU 3286 How many 0’s

洛谷 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 xy2 时;
  • 前导零状态:前导零状态应该和任意状态都能发生状态转移,即满足 ∣ x − y ∣ ≥ 2 |x - y| \ge 2 xy2,所以可以用 11 进行编码。

洛谷 P3413 萌数

链接:洛谷 P3413 萌数
题意:如果一个数包含长度至少为2的回文串,则称为萌数,求区间 [ l , r ] ( l ≤ r ≤ 1 0 1000 ) [l, r](l \le r \le 10^{1000}) [l,r](lr101000) 内萌数的个数模 ( 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) {
     
        // 前导零状态,接受0,还是保持前导零状态 
        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(n1015),求 ∏ 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=163kh(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 oddeven number,给定区间 [ l , r ] ( l ≤ r ≤ 1 0 18 ) [l, r](l \le r \le 10^{18}) [l,r](lr1018),求区间内 o d d − e v e n   n u m b e r odd-even \ number oddeven 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 AnAn1An2...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)=An2n1+An12n2+...+A22+A11给定两个数 A A A B B B ( 0 ≤ A , B ≤ 1 0 9 ) (0 \le A,B \le 10^9) (0A,B109),求区间 [ 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 928+927+...+920=9(291)=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](n10100) 中有多少合法数模(1000000007)。

  • 状态定义用两个参数表示:
第一位: 
    0    前导零状态
    1    尚未出现过递增
    2    出现过递增 

第二位:
    0-9  前缀的最后一位数字 
  • 然后进行状态转移,套用 数位 DP 模板即可。

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=1nai10ni(1ai9) 当满足以下两个条件时,我们称 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} aiai+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 1in,i<jn
现在给定区间 [ l , r ] ( l ≤ r ≤ 1 0 9 ) [l, r](l \le r \le 10^9) [l,r](lr109),求区间中 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](1lr1018)区间中的数,转换成 b ( b ≤ 10 ) b(b \le 10) b(b10) 进制后, 0 , 1 , 2... , b − 2 , b − 1 0,1,2...,b-2,b-1 0,1,2...,b2,b1 都出现偶数次的数的个数。

  • 每个数字出现 偶数次 或者 奇数次 可以用 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](lr1011) 之间的数使得这些数每个都能被 X ( X ≤ 1 0 11 ) X(X \le 10^{11}) X(X1011) 整除。

  • 分情况讨论:
  • 1)当 X ≤ 1 0 5 X \le 10^5 X105,利用 数位 DP 求解,前缀状态就是存每个数前缀模 X X X 的值;
  • 2)否则,直接暴力枚举 X X X 的倍数判可行性;

洛谷 P4127 同类分布

链接:洛谷 P4127 同类分布
题意:给出一个闭区间 [ l , r ] [l,r] [l,r],求各位数字之和能整除原数的数的个数。

  • 两个前缀状态:
  • 所有数字的和最大值为:9 * 长度 = 9 ∗ 19 < 180 = 9 * 19 < 180 =919<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) (nowsumnowmod) ,只有当 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](1lr1018) K ( 2 ≤ K ≤ 5 ) K(2 \le K \le 5) K(2K5),求区间中,十进制表示相邻 K K K 位都不同的数的个数。

  • 11 11 11 进制来表示状态,其中 [ 0 , 9 ] [0,9] [09] 代表数字, 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
  • 然后就是 二分答案 + 数位DP 判可行 了。

HDU 5965 扫雷

链接:HDU 5965 扫雷
题意:对于一个 3 × n ( n ≤ 10000 ) 3 \times n(n \le 10000) 3×n(n10000) 的格子上,中间一行均无地雷,显示了周围 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(n500) 根火柴,然后给出如下火柴的样式,求满足条件的等式 A − B = C A - B = C AB=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 42+11=91

  • 首先,如果一个数 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 xnxn1...xp+1xpxp1...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(np)+xn1(np1)+...+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=xp1+...+x2(p2)+x1(p1)
  • 由于 p p p 是平衡点,那么 l p = r p l_p = r_p lp=rp
  • 那么,如果在 p p p 是平衡点的基础上,我们来看看是否有可能, p − 1 p-1 p1 这个位置也是平衡点?
  • 假设 p − 1 p-1 p1 是平衡点,那么有:
  • 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} lp1=xn(np+1)+xn1(np)+...+xp=xn(np)+xn1(np1)+...+xp+1+(xn+xn1+...xp)=lp+k=pnxk
  • 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} rp1=xp2+...+x2(p3)+x1(p2)=xp1+...+x2(p2)+x1(p1)xp1...x2x1=rpk=1p1xk
  • 满足等式: l p − 1 = r p − 1 l_{p-1} = r_{p-1} lp1=rp1
  • 则需要满足 ∑ 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=pnxk=k=1p1xk
  • 除非 x k = 0 x_k = 0 xk=0,这种情况特殊处理,其他情况不可能满足有多个平衡点,所以可以求出所有以 p ( 1 ≤ p ≤ n ) p(1 \le p \le n) p(1pn) 为平衡点数字的和,就是整个问题的解了。

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=i10n+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=i2100n+x2+2xi10n
  • ∑ 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=(i2100n+x2+2xi10n)=i2100n+x2+2i10nx
  • 所以当最高位确定为 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 i2100n=i2a100n
  • 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 2i10nx=2i10nb
  • 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=i2a102n+2i10nb+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<LR<2631),和一个数 K ( K ≤ 10 ) K( K \le 10) K(K10),求区间中的数字表示成字符串后,最长严格递增子序列的长度为 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](lr91018)

  • 这道题比较巧妙,我们可以发现如下几个思考点:
  • 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](n20,l48,mod2520)
  • 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(n1018),求 ≥ n \ge n n 的最小超级幸运数。

  • 不用 数位 DP 也可以做,直接枚举所有答案(不到 70000 个),然后二分找。

你可能感兴趣的:(解题报告,算法,解题报告,数位DP,动态规划)