Day6 & Day7 DP

开题顺序。

CF1808C Unlucky Numbers

按数位遍历应该很好想。

一开始想的直接数位 dfs ,然后将 [ 1 , r ] [1,r] [1,r] 放到 set 里面去, [ 1 , l − 1 ] [1,l-1] [1,l1] 从 set 里删掉,set 找最小值即可。

后来找规律发现,如果 l , r l,r l,r 位数不同,一定存在一种使得所有位相同,幸运值为 0 0 0 的数。

因此我们只需要判断位数相同的情况,可以省去前缀消除影响的步骤,直接从 l l l 开始数位 dfs,记录两个状态:幸运值、可行答案。可行答案搜完 n n n 位一位一位倒推即可,用数字记录可行答案 0 0 0 的情况不好处理,可以用字符串。

代码

CF1808E2 Minibuses on Venus (medium version)

先看 easy version, n ≤ 100 , k ≤ 30 n \le 100, k \le 30 n100,k30。从反面考虑,假定最后数数位和为 S S S,则不存在 d d d 满足 2 ⋅ d ≡ 0 ( m o d k ) 2\cdot d \equiv 0 \pmod k 2d0(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=fi1,s(s+dsmodk)。代码

再看 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,k1],矩阵快速幂求 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

CF1774E Two Chess Pieces

很棒的数数题。

从棋子的角度考虑状态太多,从点的角度考虑。

当我们确定每个棋子一定需要经过哪些点,那么不论 d d d 取多少,最终的步数都是定的。对于一个棋子的必经点,一定要进去再出来,因此当两个棋子都需要经过所有点时,需要 4 ( n − 1 ) 4(n-1) 4(n1) 步。

考虑什么时候点 u u u 一定需要被一个棋子经过:

  • 子树中有该棋子。
  • 子树中有另外棋子的必经点,且存在这种点到 u u u 的距离(深度差) 大于等于 d d d

如果 u u u 不一定需要被经过,则可以少走 u u u f a u fa_u fau 这条边两遍。即初始值为 4 ( n − 1 ) 4(n-1) 4(n1) ,一个这样的点贡献为 − 2 -2 2。代码

CF1763D Valid Bitonic Permutations

有点 ex 的计数题。

主要点在于统计组合数的先后顺序。

先说两个简单的结论:

  • 不妨令 x > y x > y x>y ,不然则反转序列。
  • 转折点一定为 n n n

下面分类讨论:

如果 x = n x=n x=n,先考虑 < y <y 的部分,再考虑 ( y , x ) (y,x) (y,x) 之间的部分,答案为 ( y − 1 n − j ) × ( x − y − 1 j − i − 1 ) \dbinom {y-1} {n-j} \times \dbinom {x-y-1} {j-i-1} (njy1)×(ji1xy1)

如果 x ≠ n x \neq n x=n,枚举转折点 k k k

  • k < i k < i k<i

    先确定 < y <y 的部分,再确定 ( y , x ) (y,x) (y,x) 之间的部分,最后考虑 ( x , n ) (x,n) (x,n) 的部分,方案数为 ( y − 1 n − j ) × ( x − y − 1 j − i − 1 ) × ( n − x − 1 i − k − 1 ) \dbinom {y-1} {n-j} \times \dbinom {x-y-1} {j-i-1} \times \dbinom {n-x-1} {i-k-1} (njy1)×(ji1xy1)×(ik1nx1)

  • i < k < j i < k < j i<k<j

    先确定 < y <y 的部分,把 < y <y 多余的数扔到 i i i 左边去;再确定大于 y y y 小于 x x x 的数,部分放在 i i i 左边,剩下的放在 ( k , j ) (k,j) (k,j);最后确定 > x >x >x 的数, 部分放在 ( i , k ) (i,k) (i,k) ,剩下的放在 ( k , j ) (k,j) (k,j)。方案数为 ( y − 1 n − j ) × ( x − y − 1 y − 1 − ( i − 1 − ( n − j ) ) ) × ( n − x − 1 k − i − 1 ) \dbinom {y-1} {n-j} \times \dbinom {x-y-1} {y-1-(i-1-(n-j))} \times \dbinom {n-x-1} {k-i-1} (njy1)×(y1(i1(nj))xy1)×(ki1nx1)

组合数可以 O ( n ) O(n) O(n) 线性推,这里用的 O ( n 2 ) O(n^2) O(n2) 杨辉三角递推。

代码

CF1814E Chain Chips

好久没写 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=fi1,1,fi,1=min{fi1,0fi1,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 n1 的转移矩阵乘起来。

套个线段树优化即可。不考虑矩乘的常数,单次修改 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)。注意四倍空间。代码

CF1762F Good Pairs

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+1nfj(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+1n[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) 有三种情况:

  • a l < a r a_lal<ar,从 l l l 开始单调增走到 r r r
  • a l > a r a_l>a_r al>ar,从 l l l 开始单调减走到 r r r
  • a l = a r a_l=a_r al=ar,从 l l l 直接走到 r r 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+TnlogV)。代码。

CF1815D XOR Counting

原来是这样!

  • m = 1 m=1 m=1 n n n

  • m ≥ 3 m \ge 3 m3,考虑构造前三个数为 x , n − x 2 , n − x 2 x , \dfrac {n - x} {2} , \dfrac {n - x} {2} x,2nx,2nx,后面全部为 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 a1a2 值的不同方案数。

    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(2n1)+g(n) g ( n ) = g ( n − 1 2 ) g(n) = g(\frac {n-1} {2}) g(n)=g(2n1)

    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(2n1)) 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(2n1)

代码

CF1843F2 Omsk Metro (hard version)

一般树上路径问题都可以先考虑树退化链的情况。

先考虑链即序列问题,由于权值为正负一,值域连续,因此维护区间子段和最值即可,GSS 典题。

对于树的情况,容易想到树剖线段树维护,此题静态也可以倍增做。

倍增的一些细节

傻逼多测。

CF1826E Walk the Runway

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]);
	}

你可能感兴趣的:(游记,c++)