Atcoder Short LIS
Short LIS
计数有多少个长度为 N 的排列,满足:
- 最长下降子序列不超过 2
- A[x] = y
这里有 Q 组询问
1 ≤ N, Q ≤ 106
题解
对于一个排列“最长下降子序列不超过2” 这个条件,有很多等价的描述:
-
(NOI 2018 Day1T2)冒泡排序次数达到下界
-
可以划分成不超过2个子序列,每个子序列单调上升
-
对于每个元素均满足:要么其前面所有数都比它小,要么比它小的数都在该元素的前面
-
满足最长下降子序列不超过2的排列,一定与一种前缀max序列一一对应
因为考虑把前缀max序列中有用的值(就是单调栈中的值,也就是每一个连续段的开头)插入进序列时,为了使得最长下降子序列不超过2,就会产生从此处开始小于该数的所有数一定递增排列的限制
那么可以观察到,序列是这么一个形状:所有在前缀max上产生贡献的点形成了一个递增序列,剩下的数也形成了一个递增序列
显然一个最长下降子序列不超过2的排列一定对应了其本身的前缀max序列
而一个前缀max序列没有对前缀max产生贡献的位置填的数也是确定的,唯一对应了一个最长下降子序列不超过2的排列
分情况讨论
-
y ≥ x,那么该点一定在前缀max上。考虑反证,若其没有对前缀max产生贡献,那么x前面一定有一个大于y的数,同时x后面没有小于y的数,否则存在长度为3的下降子序列,也就是所有小于y的数都在x之前,那么至少需要1 + y − 1 = y个位置,而y ≥ x > x − 1,x前面的位置不够,矛盾
-
y < x,那么该点一定不对前缀max产生贡献。这是显然的
-
对于y < x的情况,考虑A的逆置换A−1[A[i]] = i,可以转换成另一种情况,也就是说只要考虑y ≥ x的情况。(相当于翻转坐标轴)。
考虑一个合法的前缀max序列满足的条件:
- 1 ≤ max[i] ≤ n,max[n] = n
- max[i] ≤ max[i + 1]
- i ≤ max[i]
同样放到平面上考虑。固定A[x] = y等价于确定了一部分路径,两边分别计数即可。计数也是用翻折法
那么预处理复杂度是O(N),单次询问复杂度是O(1)
CO int N=2e6+10;
int fac[N],ifac[N];
IN int C(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
int n=read<int>();
fac[0]=1;
for(int i=1;i<=2*n;++i) fac[i]=mul(fac[i-1],i);
ifac[2*n]=fpow(fac[2*n],mod-2);
for(int i=2*n-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
int A=read<int>(),B=n-1-read<int>();
if(A>B) swap(A,B);
int ans=add(C(A+B,A),mod-C(A+B,B+1));
ans=mul(ans,add(C(2*n-2-A-B,n-1-A),mod-C(2*n-2-A-B,n-A)));
printf("%d\n",ans);
return 0;
}