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. 1 ≤ max[i] ≤ n,max[n] = n
  2. max[i] ≤ max[i + 1]
  3. 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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/autoint/p/12522079.html