9.27
Balanced Subsequences —— 不知道坐标怎么动的时候就画图!
首先知道结论:折现图上最低点的纵坐标为 \(k-m\)。
简单证明:考虑贪心这匹配过程(左括号 +1,右括号 -1),每次如果遇到向下的小于 0 的段,我们把其抹平,然后让后面所有点都 + 上某个值,最后一直这样操作,答案就是在 y 正轴上面的右括号/-1/下降个数。
感性理解就是对于那个最低的在 y 负半轴的位置,显然前面的所有的移动都不会超过这一次的移动,然后这一次移动过后,根据最低点的性质,后面也必定不会 < 0,得证。
问题变成:
从 \((0,0)\) 到 \((n+m,n-m)\) 的折线图经过但不穿过 \(y=k-m\) 的方案数。
Conclusion
-
贪心模拟匹配过程。
-
将过程刻画到折线图上。
-
挖掘出简单性质。
-
转换成格子的非降序列计数,卡特兰计算。
-
不知道坐标怎么动的时候就画图。
Counting Prefixes
给定长度为 \(n\) 的数列 \(p\),求有多少个长度为 \(n\) 的数列 \(a\) 满足:\(\forall i\in[1,n],|a_i|=1\);其前缀和数组排序后恰为数列 \(p\)。\(\sum n\leq 5000\)。
这个题真的抽象,还是先不管了。
Conclusion
-
用折线图观察操作。
-
自定义统一操作生成最终答案。
-
题外话:感觉连续段 dp 也可做?https://www.luogu.com.cn/article/i8kmk5tr
Interesting Sections
给你一个长为 \(n\) 的非负整数序列 \(a\),求有多少区间 \([l,r]\) 满足 \(\text{popcount}(\max\limits_{i=l}^r a_i)=\text{popcount}(\min\limits_{i=l}^r a_i)\)。\(1\le n\le 10^6,0\le a_i\le 10^{18}\)。
Conclusion
- Min/Max 分治模型:
所以这个题我们 \(i\) 从 \(mid\) 到 \(l\) 走,动态指针维护 \(p,q\),然后分别计算这三段的贡献。(对于每个 \(l\) 计算合法的 \(r\))
具体来说每次枚举的就是 \(l'\),然后看 \(r'\) 在 \((mid,p],(p,q],(q,r]\) 分别有多少个即可。最麻烦的是第 2 种计算,这个时候我们讨论是哪一个在左边。
void dfs(int l, int r) {
if(l == r) return ans ++, void();
int mid = l + r >> 1;
dfs(l, mid);
dfs(mid + 1, r);
pre[mid] = 0; mx[mid] = -1e18, mn[mid] = 1e18;
for(int i = mid + 1;i <= r; ++i)
mx[i] = max(mx[i-1], a[i]), mn[i] = min(mn[i-1], a[i]),
pre[i] = pre[i - 1] + (pc(mx[i]) == pc(mn[i]));
// 我们的桶维护 (p1, p2] 的 pop 个数
for(int i = mid, maxn = -1, minn = 1e18, p1 = mid, p2 = mid;i >= l; --i) {
maxn = max(maxn, a[i]), minn = min(minn, a[i]);
// p1
while(p1 < r and maxn >= mx[p1 + 1] and minn <= mn[p1 + 1]) {
++p1;
--cnt1[pc(mx[p1])], --cnt2[pc(mn[p1])];
}
// p2
while(p2 < r and (maxn >= mx[p2 + 1] or minn <= mn[p2 + 1])) {
++p2;
++cnt1[pc(mx[p2])], ++cnt2[pc(mn[p2])];
}
// 1. <= p1
if(pc(maxn) == pc(minn)) ans += p1 - mid;
// 2. p1 < x <= p2,也就是一边 max 一边 min,比较有难度,分讨 maxmin 在哪边
if(maxn >= mx[p2]) // max 在左边
ans += cnt2[pc(maxn)]; // min
else // min 在左边
ans += cnt1[pc(minn)];
// 3. > p2,max/min 都在右边,左边完全不影响
ans += pre[r] - pre[p2]; // 那么就看 max 和 min pc 相等的 r' 个数即可
}
memset(cnt1, 0, sizeof cnt1); memset(cnt2, 0, sizeof cnt2);
}
Maximums and Minimums
求有多少区间的最大值是最小值的倍数。
枚举最大值和因数,注意到 \(10^6\) 以内的因数最多只有 \(240\) 个。
有区间 \([l,r]\) 表示最大值的区间,要 \(O(1)\) 判断 \(d\) 是区间里面的最小值。
-
\(d\) 在区间里面有值。(除了 \(i\) 以外)
-
区间里面没有比 \(d\) 小的数。
对于第二个限制我们直接根据单调栈预处理可以求出 \(d\) 作为最小值的区间,和最大值区间交一下应该就行。考虑第一个。
Conclusion
-
\(O(1)\) 地找一个数前面的某一个任意值的最大位置以及后面那个值的最小位置:
考虑从 \(1\sim i\) 的过程中,维护每个元素的出现次数并且给每个值维护一个
vector
,这样当前
vector
里面前驱位置就是下标 \(cnt_x\) 对应的值。 -
这里分类讨论需要注意一下 2 种:只交 1 个左/右的,两个都交的情况。注意区间左右端点,细节很多。
-
还有就是预处理时相等元素怎么搞的问题。每个最大值按照经典套路一边取等即可,枚举的最小值区间感性理解应该都是取等的。