注意到,要求一个值域是 \(\{1,-1\}\) 的序列的子段和有多少种不同的取值,实际上就是求它的最小子段和 \(a\) 到最大子段和 \(b\) 之间有多少个整数。因为可以证明,每个处于 \([a,b]\bigcap Z\) 中的数,都至少有一个子段与之对应——要得到和为 \(b-1\) 的子段,只需要从最大子段的一端删去一个和为 \(1\) 的子段即可(一定可以做到),进而可以一步一步得到 \(b-2,b-3,\cdots 1,0\);相似的,从最小子段和可以一步一步得到 \(a+1,a+2,\cdots -1,0\)。
有了上述结论,我们可以对特殊值 \(x\) 左右两边的只含 \(1,-1\) 的段 dp 求最大子段和 \(\max\)、最小子段和 \(\min\),把 \([\min,\max]\bigcap Z\) 中的数全部加入 set。对于含 \(x\) 的区间,可以求出左段的最大后缀和 \(\max_1\) 和最小后缀和 \(\min_1\),以及右段的 \(\max_2,\min_2\),取值范围就是 \([\min_1+\min_2+x, \max_1+\max_2+x]\bigcap Z\),同样加入 set。遍历的值域不超过 \(n\),复杂度 \(O(n\log n)\);也可以用线段树优化到 \(O(\log n)\)。AC代码
标签:一步,子段,max,Segments,min,Sums,bigcap,CF2043C,可以 From: https://www.cnblogs.com/th19/p/18635798