• [loj#2719] [NOI2018] 冒泡排序


    题意简述

    冒泡排序的交换次数下界为 (frac{1}{2}sum |i-p_i|)
    对于长度为 (n) 的排列,定义交换次数为 (frac{1}{2}sum |i-p_i|) 的排列为 “好”排列
    给定长度为 (n) 的排列 (q),求字典序严格大于 (q) 的“好”排列个数

    (n leq 6 imes 10^5)


    想法

    Step1 找性质

    首先探究“好”排列的性质。
    根据题目中的“提示”:

    排序本质上就是数字的移动,因此排序的交换次数应当可以用数字移动的总距离来描述。对于第 (i) 个位置,假设在初始排列中,这个位置上的数字是 (p_i),那么我们需要将这个数字移动到第 (p_i) 个位置上,移动的距离是 (|i-p_i|) 。从而移动的总距离就是 (sum |i-p_i|) ,而冒泡排序每次会交换两个相邻的数字,每次交换可以使移动的总距离至多减少 2 。因此 (frac{1}{2}sum |i-p_i|) 是冒泡排序的交换次数的下界。

    可知“好”排列中一个数要么一直往左边挪,要么一直往右边挪
    具体地说,设排列 (p) 中数 (i) 的位置为 (b_i)

    • (b_i<i)(i) 要一直往右挪,也就是说排在 (i) 左边的数都小于 (i) ,所有包含 (i) 的逆序对都是 (i) 与右侧的数
    • (b_i>i) : (i) 要一直往左挪,也就是说排在 (i) 右边的数都大于 (i) ,所有包含 (i) 的逆序对都是 (i) 与左侧的数
    • (b_i=i)(i) 不能挪动,排在 (i) 左侧的数都小于 (i) ,排在 (i) 右侧的数都大于 (i) ,不存在包含 (i) 的逆序对

    也就是说对每个数 (i) ,最多只能与一侧的数构成逆序对。
    思考下发现,这个条件也是充分的。只要满足“最多只能与一侧的数构成逆序对”,就一定满足上面三个条件之一,可推出是“好”排列。
    性质挖掘完毕。

    Step2 特殊情况下的 dp 方程

    先忽略“字典序”的要求,考虑如何计数长度为 (n) 的“好”排列个数
    考虑一位位填数,假设当前填了 (k) 位,其中的最大数为 (mx),那么对于当前未填的 (<mx) 的数来说,左边已构成逆序对了,右侧不能再有了,所以这些数填的顺序是递增的;而对于未填的 (>mx) 的数,暂时可以随便填

    于是设状态 (f[i][j]) 表示还有 (i) 位没有填,有 (j) 个数不被限制,显然它们是剩余数中最大的 (j) 个数
    那么这位可填被限制的数中最小的那个,或任一个不受限制的
    (f[i][j]=f[i-1][j]+sumlimits_{k=0}^{j-1} f[i-1][k]=sumlimits_{k=0}^j f[i-1][k]=f[i][j-1]+f[i-1][j])
    边界为 (f[0][0]=1)

    这个 (dp) 让我们想到了走格子,(f[m][n]) 表示从 ((0,0)) 走到 ((m,n)) ,每步可以向右或向上走,任何时候向上步数不能超过向右步数的总方案数。
    所有不合法情况都可与从 ((-1,1)) 走到 ((m,n)) 的路径一一对应(不合法 (Leftrightarrow) 与直线 (y=x+1) 有交点,把 ((0,0)) 到第一次交点的路径关于 (y=x+1) 对称,形成的即是 ((-1,1))((m,n)) 的路径)
    所以,(f[m][n]=inom{m+n}{m}-inom{m+n}{m+1})

    Step3 拓展到一般情况

    考虑“字典序”条件,从高位到低位枚举首个大于的位置 (k),这个位置要填的数 (>q_k)
    (q_1,q_2,dots q_k) 中的最大数为 (mx)
    (q_kgeq mx) ,则此时要填的数位已填部分的最大数,则剩下的数(包括第 (k) 位的数)填法为 (sumlimits_{i=0}^{n-mx-1} f[n-k][i]=f[n-k+1][n-mx+1])
    (q_k<mx) ,如果第 (k) 位填的数 (t)(mx) 小,而 (t>q_k)(q_k)(t) 后面会形成逆序对,不符合条件。所以第 (k) 位填的数 (geq mx),填法同样为 (f[n-k+1][n-mx+1])

    最后注意判断当前前缀是否满足条件(可用树状数组),若不满足直接跳出。


    总结

    技巧

    走格子那个挺套路,以及 (m=n) 时是卡特兰数的公式

    感想

    挖掘性质最费劲……有时候分类讨论后情况比较复杂,可以考虑有没有更简要的条件可以概括上面的多种情况~


    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    #define P 998244353
    
    using namespace std;
    
    int read(){
    	int x=0;
    	char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    
    const int N = 600005;
    
    int n,q[N];
    int mul[N*2],inv[N*2];
    
    int Plus(int x,int y) { return x+y<P?x+y:x+y-P; }
    int Minus(int x,int y) { return x>=y?x-y:x-y+P; }
    int Pow_mod(int x,int y){
    	int ret=1;
    	while(y){
    		if(y&1) ret=1ll*ret*x%P;
    		x=1ll*x*x%P;
    		y>>=1;
    	}
    	return ret;
    }
    
    int f(int x,int y) { //x>=y
    	if(x<y) return 0;
    	if(y<0 || x<0) return 0;
    	if(y==0) return 1;
    	return Minus(1ll*mul[x+y]*inv[x]%P*inv[y]%P,1ll*mul[x+y]*inv[x+1]%P*inv[y-1]%P);
    }
    
    int c[N];
    void add(int x,int y) { while(x<=n) c[x]+=y,x+=x&(-x); }
    int sum(int x){
    	int ret=0;
    	while(x) ret+=c[x],x-=x&(-x);
    	return ret;
    }
    
    int main()
    {
    	freopen("inverse.in","r",stdin);
    	freopen("inverse.out","w",stdout);
    	int T=read();
    	
    	mul[0]=1;
    	for(int i=1;i<N*2;i++) mul[i]=1ll*mul[i-1]*i%P;
    	inv[N*2-1]=Pow_mod(mul[N*2-1],P-2);
    	for(int i=N*2-2;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%P;
    	
    	while(T--){
    		n=read();
    		for(int i=1;i<=n;i++) q[i]=read();
    		
    		int mx=1,ans=f(n,n-q[1]-1);
    		add(q[1],1);
    		for(int i=2;i<=n;i++){
    			if(q[i]<q[mx]){
    				ans=Plus(ans,f(n-i+1,n-q[mx]-1));
    				if(sum(q[i]-1)<q[i]-1) break;
    			}
    			else{
    				mx=i;
    				ans=Plus(ans,f(n-i+1,n-q[i]-1));
    			}
    			add(q[i],1);
    		}
    		printf("%d
    ",ans);
    		
    		//clear
    		for(int i=0;i<=n;i++) c[i]=0;
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    机器学习算法的流程总结
    机器学习算法的流程总结
    路由器的原理
    路由器的原理
    机器学习编程接口(api)设计(oop 设计)
    机器学习编程接口(api)设计(oop 设计)
    组态档(configuration file)与建构档
    组态档(configuration file)与建构档
    学习之法 —— 套路
    学习之法 —— 套路
  • 原文地址:https://www.cnblogs.com/lindalee/p/13337911.html
Copyright © 2020-2023  润新知