开题顺序。
按数位遍历应该很好想。
一开始想的直接数位 dfs ,然后将 [ 1 , r ] [1,r] [1,r] 放到 set 里面去, [ 1 , l − 1 ] [1,l-1] [1,l−1] 从 set 里删掉,set 找最小值即可。
后来找规律发现,如果 l , r l,r l,r 位数不同,一定存在一种使得所有位相同,幸运值为 0 0 0 的数。
因此我们只需要判断位数相同的情况,可以省去前缀消除影响的步骤,直接从 l l l 开始数位 dfs,记录两个状态:幸运值、可行答案。可行答案搜完 n n n 位一位一位倒推即可,用数字记录可行答案 0 0 0 的情况不好处理,可以用字符串。
代码
先看 easy version, n ≤ 100 , k ≤ 30 n \le 100, k \le 30 n≤100,k≤30。从反面考虑,假定最后数数位和为 S S S,则不存在 d d d 满足 2 ⋅ d ≡ 0 ( m o d k ) 2\cdot d \equiv 0 \pmod k 2⋅d≡0(modk)。dp 即可,记 f i , s f_{i,s} fi,s 表示选到第 i i i 位, i i i 位数位和为 s s s 的方案数, f i , s ′ = ∑ f i − 1 , s ( s + d ≡ s ′ m o d k ) f_{i,s'} = \sum f_{i-1,s}(s+d \equiv s'\bmod k) fi,s′=∑fi−1,s(s+d≡s′modk)。代码
再看 medium version,对于每个 S S S 有一个固定的转移矩阵 G G G,记 F i = [ f i , 0 f i , 1 . . . f i , k − 1 ] F_i = \begin{bmatrix}f_{i,0} & f_{i,1} & ... f_{i,k-1}\end{bmatrix} Fi=[fi,0fi,1...fi,k−1],矩阵快速幂求 F 0 × G n F_0 \times G^n F0×Gn,时间复杂度 O ( k 4 log n ) O(k^4 \log n) O(k4logn),无法通过此题。
需要更优的方法。
dzy 强者做法:link
很棒的数数题。
从棋子的角度考虑状态太多,从点的角度考虑。
当我们确定每个棋子一定需要经过哪些点,那么不论 d d d 取多少,最终的步数都是定的。对于一个棋子的必经点,一定要进去再出来,因此当两个棋子都需要经过所有点时,需要 4 ( n − 1 ) 4(n-1) 4(n−1) 步。
考虑什么时候点 u u u 一定需要被一个棋子经过:
如果 u u u 不一定需要被经过,则可以少走 u u u 到 f a u fa_u fau 这条边两遍。即初始值为 4 ( n − 1 ) 4(n-1) 4(n−1) ,一个这样的点贡献为 − 2 -2 −2。代码
有点 ex 的计数题。
主要点在于统计组合数的先后顺序。
先说两个简单的结论:
下面分类讨论:
如果 x = n x=n x=n,先考虑 < y
如果 x ≠ n x \neq n x=n,枚举转折点 k k k:
若 k < i k < i k<i
先确定 < y
若 i < k < j i < k < j i<k<j
先确定 < y
组合数可以 O ( n ) O(n) O(n) 线性推,这里用的 O ( n 2 ) O(n^2) O(n2) 杨辉三角递推。
代码
好久没写 ddp 的题了,写得很爽。
对一个环移动使得错排,其代价为 2 × ∑ w 2 \times\sum w 2×∑w,容易发现就是一个分组 dp。
记 f i , 0 / 1 f_{i,0/1} fi,0/1 表示在前 i i i 条边中,第 i i i 条边选 / 不选的错排的最小花费,有: f i , 0 = f i − 1 , 1 , f i , 1 = min { f i − 1 , 0 f i − 1 , 1 } + 2 × w i f_{i,0}=f_{i-1,1},f_{i,1} = \min \{ f_{i-1,0} f_{i-1,1}\} + 2 \times w_i fi,0=fi−1,1,fi,1=min{fi−1,0fi−1,1}+2×wi,初始 f 0 , 0 = 0 , f 0 , 1 = + ∞ f_{0,0} = 0, f_{0,1} = +\infin f0,0=0,f0,1=+∞。
可以用广义矩阵优化。
一般的矩阵乘法: C i , j = ∑ k ( A i , k × B k , j ) C_{i,j} = \sum_k (A_{i,k} \times B_{k,j}) Ci,j=k∑(Ai,k×Bk,j)
× \times × 对 ∑ \sum ∑ 运算具有分配律, ( a + b ) × c = a × c + b × c (a+b) \times c = a \times c + b \times c (a+b)×c=a×c+b×c。结论是后者有结合律且后者对前者具有分配律,就可以矩阵乘法。
把 ∑ \sum ∑ 换成取 min \min min, × \times × 换成 + + +, min ( a , b ) + c = min ( a + c , b + c ) \min(a,b) + c = \min (a+c,b+c) min(a,b)+c=min(a+c,b+c),具有分配律。
有 [ f i , 0 f i , 1 ] = [ f i , 0 f i , 1 ] [ + ∞ 2 × w i 0 2 × w i ] \begin{bmatrix} f_{i,0} & f_{i,1} \end{bmatrix} = \begin{bmatrix} f_{i,0} & f_{i,1}\end{bmatrix} \begin{bmatrix} +\infin & 2 \times w_i \\ 0 & 2 \times w_i \end{bmatrix} [fi,0fi,1]=[fi,0fi,1][+∞02×wi2×wi]
答案就是 [ f 0 , 0 f 0 , 1 ] \begin{bmatrix} f_{0,0} & f_{0,1} \end{bmatrix} [f0,0f0,1]和 1 1 1 到 n − 1 n-1 n−1 的转移矩阵乘起来。
套个线段树优化即可。不考虑矩乘的常数,单次修改 O ( log n ) O(\log n) O(logn),单次查询 O ( 1 ) O(1) O(1),总 O ( n log n + m log n ) O(n \log n + m \log n) O(nlogn+mlogn)。注意四倍空间。代码
P1
先不考虑绝对值,仅考虑每次走到的数单调增,且走到的相邻两数相差不超过 k k k。 ( l , r ) (l,r) (l,r) 合法就是 l l l 能走到 r r r,统计合法 ( l , r ) (l,r) (l,r) 对数。
记 f i f_i fi 表示以 i i i 为左端点,与之匹配的右端点个数。显然与 i i i 匹配的右端点可以不止走一步。
一开始想的 f i = ∑ j = i + 1 n f j ( a j ∈ [ a i + 1 , a i + k ] ) f_i = \sum\limits_{j=i+1}^{n} f_j (a_j \in [a_i+1,a_i+k]) fi=j=i+1∑nfj(aj∈[ai+1,ai+k]),但这样会重复计算。
记 j j j 为从 i + 1 i+1 i+1 开始第一个满足 a j ∈ [ a i + 1 , a i + k ] a_j \in [a_i+1,a_i+k] aj∈[ai+1,ai+k],有: f i = f j + ∑ k = i + 1 n [ a k ∈ [ a i + 1 , a j ] ] f_i = f_j+\sum\limits_{k=i+1}^n [a_k \in [a_i+1,a_j]] fi=fj+k=i+1∑n[ak∈[ai+1,aj]]。解释一下, f j f_j fj 一定包含了所有 a > a j a> a_j a>aj 的右端点,还有一些右端点的 a ∈ [ a i + 1 , a j ] a\in [a_i+1,a_j] a∈[ai+1,aj],加上这一部分。倒序枚举 i i i,即求当前枚举的数中在给定值域区间内的个数,可以用权值树状数组 / 线段树维护。
P2
而在原题目中,合法的 ( l , r ) (l,r) (l,r) 有三种情况:
第二种可以通过翻转化为第一种,用 P1 方法解决。第三种特判即可。
权值线段树初始化复杂度 O ( V log V ) O(V \log V) O(VlogV), V V V 为值域。每次询问都全部初始化会超时,考虑每组询问后撤销更改。时间复杂度 O ( V log V + T ⋅ n log V ) O(V \log V + T \cdot n \log V) O(VlogV+T⋅nlogV)。代码。
原来是这样!
m = 1 m=1 m=1, n n n。
m ≥ 3 m \ge 3 m≥3,考虑构造前三个数为 x , n − x 2 , n − x 2 x , \dfrac {n - x} {2} , \dfrac {n - x} {2} x,2n−x,2n−x,后面全部为 0 0 0,其中 x x x 与 n n n 同奇偶。
这样的序列异或和就是 x x x,可以取到 [ 1 , n ] [1,n] [1,n] 中与 n n n 奇偶性相同的所有值。由于 ∑ i = 1 m a i \sum_{i=1}^m a_i ∑i=1mai 与 ⨁ i = 1 m a i \bigoplus_{i=1}^m a_i ⨁i=1mai 奇偶性相同,并且后者小于等于前者,因此至多能取这些数。
m = 2 m=2 m=2,即 a 1 + a 2 = n a_1+a_2=n a1+a2=n,求 a 1 ⊕ a 2 a_1 \oplus a_2 a1⊕a2 值的不同方案数。
记 g n g_n gn 表示和为 n n n 的不同异或值个数, f n f_n fn 表示和为 n n n 的不同异或值之和。
若 a 1 + a 2 = n a_1+a_2=n a1+a2=n 为奇数,将最后一位 1 1 1 去掉, f ( n ) = 2 f ( n − 1 2 ) + g ( n ) f(n) = 2 f(\frac {n-1} {2})+g(n) f(n)=2f(2n−1)+g(n), g ( n ) = g ( n − 1 2 ) g(n) = g(\frac {n-1} {2}) g(n)=g(2n−1)。
若 a 1 + a 2 = n a_1+a_2=n a1+a2=n 为偶数,考虑最后一位进不进位, f ( n ) = 2 ( f ( n 2 ) + f ( n 2 − 1 ) ) f(n) = 2 ( f(\frac {n} {2} )+ f(\frac {n} {2} - 1)) f(n)=2(f(2n)+f(2n−1)), g ( n ) = g ( n 2 ) + g ( n 2 − 1 ) g(n) = g(\frac {n} {2} )+ g(\frac {n} {2} - 1) g(n)=g(2n)+g(2n−1)。
代码
一般树上路径问题都可以先考虑树退化链的情况。
先考虑链即序列问题,由于权值为正负一,值域连续,因此维护区间子段和最值即可,GSS 典题。
对于树的情况,容易想到树剖线段树维护,此题静态也可以倍增做。
倍增的一些细节
傻逼多测。
m m m 维偏序问题。
考虑用图的方式呈现问题, u , v u,v u,v 间有边表示 u , v u,v u,v 可以同时被选择。
按照偏序转有向边,拓扑 dp,时间复杂度 O ( n 2 m + n + m ) O(n^2m+n+m) O(n2m+n+m),瓶颈在于判断合法。
高维偏序问题常见的 bitset 优化。用 bitset 维护 ( u , v ) (u,v) (u,v) 是否合法,时间复杂度 O ( n 2 m w + n + m ) O(\frac {n^2m}{w}+n+m) O(wn2m+n+m),可以通过此题。
具体来说,我们需要维护 m m m 张 n × n n \times n n×n 的表 A A A,表上 A k ( i , j ) = 1 A_k(i,j)=1 Ak(i,j)=1 表示在第 k k k 维 i i i 和 j j j 满足偏序关系。将 m m m 张表按位与的结果即可以求出满足 m m m 维偏序的点对。
// 朴素 for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) A[i][j] = 1; for(int i=1; i<=m; i++) { for(int j=1; j<=n; j++) cin >> r[j]; for(int u=1; u<=n; u++) for(int v=1; v<=n; v++) A[u][v] &= (r[u] < r[v]); }