• 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;
    }
    
  • 相关阅读:
    全栈必备Linux 基础
    Linux 的 Socket IO 模型
    Vim
    Linux 下使用 Sar 简介
    提高效率,推荐 5 款命令行工具
    Vim小技巧
    剑指Offer 矩形覆盖
    剑指Offer 变态跳台阶
    剑指Offer 跳台阶
    2016 网易校招内推C/C++第二场8.6
  • 原文地址:https://www.cnblogs.com/autoint/p/12522079.html
Copyright © 2020-2023  润新知