https://codeforces.com/contest/2101
D Mani and Segments
给定1~n排列,问有多少子串满足
LIS+LDS=len+1
3s
我的思路
排列保证了两两不同
lis: dp[i] = idx_lower_bound(a[i])-1
显然 lis 和 lds如果两两不同,那么它们的共有元素最多有一个
有一个共有元素时: lis-1 + lds-1 + 1 <= size(所有元素) = len
(len+1) - 1 <= size(所有元素) = len
没有有元素时: lis + lds <= size(所有元素) = len
(len+1) <= size(所有元素) = len
说明了 恰好有一个共有元素,且两个序列占满整个数组
钦定这个共有元素
它向左延伸,要么链接更小要么链接更大, 必须要满足匹配,向右同理
1 2 3 4 5 6 7 8 9 10
| fix i min = a[i] max = a[i] for j = i+1 ... n: if a[j] > max: max=a[j] elif a[j] < min: min = a[j] else: break
|
当出现纯单调序列时,这个共有元素不是唯一的
1 3 4 5 6 2, 这样共有也不是唯一的, 上面方案没有完成去重的问题
1 4 3 2 5, 这样 共有的一定不是最大或者最小,
校验方案:
dp[i][0] = i作为下降时, 上升侧的最小值
dp[i][1] = i作为上升时, 下降侧的最大值
dp[i][0] = min(dp[i-1][0] if a[i] < a[i-1], a[i-1] if a[i] < dp[i][1], INF)
dp[i][1] = max(dp[i-1][1] if a[i] > a[i-1], a[i-1] if a[i] > dp[i][0], -INF)
这个dp会受到 前面内容的影响, 感觉局部性还不如钦定共有
反面: 什么是不合法的
a<b,c<d
d b
c a
a,b无法同时连bc,所以一个连b一个连c,显然不行, 其中a,d相邻
好像也不好搞
另一个角度 如果 a[l..r] 合法
那么 a[l..mid], a[mid…r] 也合法,因为从共有元素角度看,如果包含,那么就有包含的方案,如果不包含发生了分裂,也就是 切割的mid处 可以作为共有点
所以 合法的l..r 的任何切割 总有一半是切割点是共有点
还是单独来,就钦定共有点,但是保证共有点是可选区间最左点