CF好题_Oct

D. Training Session
给定n个互不完全相同的 ( x , y ) (x,y) (x,y)对,统计有几个三元组,满足 x x x互不相同或 y y y互不相同
https://codeforces.com/contest/1598/problem/D

题解:组合,正难则反,注意条件中的互不相同!

B. Frog Traveler
一开始在位置 n n n,对于每个位置,你可以向上跳 [ 0 , a i ] [0,a_i] [0,ai],但是到每个位置后,你会向下滑 b i b_i bi,问最少跳几次到达位置 0 0 0
https://codeforces.com/contest/1601/problem/B

题解:BFS-style DP,记 f i f_i fi表示从 n n n i i i (还没滑下去)所需最小步数,从 n n n开始更新,显然先被更新到的就找到最小的了,又由于每个点 i i i能更新的点是 [ i + b i − a i − b i , i + b i ] [i+b_i-a_{i-b_i},i+b_i] [i+biaibi,i+bi],即从更后面开始往前的区间,所以整个更新过程的区间一定是不跳跃的,是从尾部逐渐推进的,所以满足单调性,可以 O ( n ) O(n) O(n)解决
Tips: BFS-style DP,每个点只有1次机会去更新别人,如果更新的是区间,也可以线段树,但是这题区间连续于是就是 O ( n ) O(n) O(n)了。实现的时候和BFS一样用队列存,先进先出。

C. Optimal Insertion
给定2个数列{a},{b},要求把b中的数字任意插入a中,也就是a的顺序不变,b的顺序可变。要求插入后逆序对最少,求之
https://codeforces.com/contest/1601/problem/C

题解 :逆序数,性质比较难发现,也就是每个 b b b找到自己局部最优位置的时候,一定可以达到全局最优。简单意会就是,小的数肯定更喜欢往前跑,大的数往后跑,自然就能保证 a b ab ab交互的最优也是 b b b的最优( b b b递增序)。简单证明by caoyang1123:假设 b i b_i bi增大,然后它的最优位置反而左移,那么左边一定存在一些比当前 b i b_i bi大的值,左移过了这些值才能更优,但是原来bi更小,因此左移过这些值对之前也更优,矛盾。
问题转化为找每个 b b b的最佳插入位置,我们记 p i p_i pi表示插入到 a p i a_{p_i} api之前,所以 p i = n + 1 p_i=n+1 pi=n+1表示插到末尾。
1.显然我们按 b b b 顺序处理,不妨升序
2.考虑 b i + 1 b_{i+1} bi+1 带来的改变量,只有 b i ≤ a ≤ b i + 1 b_i \leq a \leq b_{i+1} biabi+1 a a a 会产生影响,这样更新显然每个 a a a 只会出现一次(?)
3.考虑怎么影响,我们假设一开始是一个极小的数字,即每个 a a a都对后面位置有一个贡献。当 a a a大于等于 b b b的时候要去掉对后影响, a a a大于 b b b的时候要加上对前影响,所以其实好麻烦,要两个指针。
总结:线段树+单调指针扫过去更新

法2:我们深度挖掘一下性质,考虑到如果找到了 b m i d b_{mid} bmid的位置 p m i d p_{mid} pmid那么其他数字只能在左右两边,所以可以尝试用分治法(类似快排),每层类似法1也是加加减减,但是是暴力重新统计

E. Arena
当前有 n n n个数,则每个数减 n − 1 n-1 n1,此时若某个数小于等于 0 0 0则被淘汰,存活的 n ′ n' n个人重复以上操作,给定 n n n和最大数字 k k k,初始数字要在 [ 1 , k ] [1,k] [1,k]之内,问有几种初始情况下,不会产生最终(不死的)胜利者
1 ≤ n , k ≤ 500 1 \leq n,k \leq 500 1n,k500
https://codeforces.com/contest/1606/problem/E

题解 :DP+组合,题目类型是比较显然的,考虑怎么设计状态。
第一种想法是直接基于组合的,如 f [ i ] [ j ] f[i][j] f[i][j]表示 i i i个人,最大数字(且取到) j j j,考虑能否 O ( n ) O(n) O(n)地扫一遍 f [ i − 1 ] [ k ] f[i-1][k] f[i1][k]并结合组合知识搞定,不过这道题显然不可以(?)
第二种想法是基于模拟的,这种一轮一轮的游戏就很适合用这种方法,显然除了上文的 i , j i, j i,j,转移时我们最关心的是小于等于 i − 1 i-1 i1的人有几个,记为 k k k
则dp转移方向是 f [ i ] [ j ] [ k ] ← f [ i − k ] [ j − i + 1 ] [ . . . . ] f[i][j][k] \leftarrow f[i-k][j-i+1][....] f[i][j][k]f[ik][ji+1][....]
结合组合知识: f [ i ] [ j ] [ k ] = ∑ C i k ∗ ( i − 1 ) k ∗ f [ i − k ] [ j − i + 1 ] [ l ] f[i][j][k]=\sum C_i^k*(i-1)^k*f[i-k][j-i+1][l] f[i][j][k]=Cik(i1)kf[ik][ji+1][l]
解释:谁死*死的时候是 [ 1 , i − 1 ] [1,i-1] [1,i1]哪个值
然后我们惊喜的发现,这个 l l l非常没有存在感,直接合并就好了,或者直接O(n)记一下,每个 k k k直接用也是可以保证复杂度正确的
合并后即 f [ i ] [ j ] = ∑ k C i k ∗ ( i − 1 ) k ∗ f [ i − k ] [ j − i + 1 ] f[i][j]=\sum_k C_i^k*(i-1)^k*f[i-k][j-i+1] f[i][j]=kCik(i1)kf[ik][ji+1]
初值即游戏结束状态, f [ 1 ] [ j ] = 1 f[1][j]=1 f[1][j]=1 f [ 1 ] [ j ] [ 0 ] = 1 f[1][j][0]=1 f[1][j][0]=1
(其实我不是很分得清到底是=n还是=1,实际上是=1,但是我太菜了,想不清楚)

D. Difficult Mountain
一开始有 n n n个人,爬山难度 d d d,爬山难度会改变,记之后的爬山难度为 d ′ d' d。第 i i i个人可以爬上 d ′ ≤ s i d' \leq s_i dsi的山,但是第 i i i个人爬完后,爬山难度 d ′ = m a x ( d ′ , a i ) d'=max(d',a_i) d=max(d,ai),求最多能爬上去几个人
https://codeforces.com/contest/1602/problem/F

题解:感觉很贪心,我们故技重施,考虑两个人:若两个人都是 s > a s>a s>a,我们肯定希望把 s s s大的放后面;若两个人都是 s ≤ a s \leq a sa,如果二选一的话,我们肯定希望选前者,如果有可能两个都选的话,我们肯定希望 a a a大的在后;若一个是 a a a大,一个是 s s s大,如果其中是 s m a x ≥ a m a x s_{max} \geq a_{max} smaxamax,显然是把 s m a x s_{max} smax放后面,完美衔接还不会更劣,如果是 s m a x < a m a x s_{max} < a_{max} smax<amax,显然还是把 s m a x s_{max} smax放前面,否则 s m a x s_{max} smax这样一个不会更劣的好人肯定没机会选上了,然后 a m a x a_{max} amax能不能取到,后面的人能不能接上那就不是这两个人考虑的事情了。综上,按 m a x ( s , a ) max(s,a) max(s,a)排序后模拟

D. Red-Blue Matrix
n ∗ m n*m nm的矩阵按行染色并按列划分成两部分,要求左边的红色都大于左边的蓝色,右边的红色都小于右边的蓝色。若可以,给出方案
n , m ≤ 5 e 5 , n m ≤ 1 e 6 n,m \leq 5e5,nm \leq 1e6 n,m5e5nm1e6
https://codeforces.com/contest/1606/problem/D

题解:题目要求的方案是非常严格的,但也非常复杂不好处理,我们可以弱化条件!我们按照每行第一个数重排每一行,显然此时可能的染色只能是横切一刀,划分是竖切一刀,我们可以从四个角开始预处理就可以 O ( 1 ) O(1) O(1)判断方案是否合法,综上 O ( n l o g n + n m ) O(nlogn+nm) O(nlogn+nm)

你可能感兴趣的:(算法)