zoukankan      html  css  js  c++  java
  • UOJ#394. 【NOI2018】冒泡排序

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ394.html

    题解

    首先我们发现一个数不能既被往左换又被往右换。也就是说不能有任何一个数左边有比他大的,又被有比他小的。

    也就是最长下降子序列长度不超过 2 。

    所以我们一定可以找到 2 个上升序列包含所有的数。

    于是容易想到 $O(n^2)$ 的 dp:

    $dp_{i,j}$ 表示加入了 $i$ 个数,最大值为 $j$ 的情况下,填完的方案数。

    那么,如果下一个数小于 $i$ ,那肯定是填小于 $j$ 的第一个,否则就是填一个比 $j$ 更大的值。

    我们把这个东西看做括号序列,填一个比 $j$ 大的值就相当于加入若干个左括号,然后再加入一个右括号;填一个比 $j$ 小的数字就相当于加入一个右括号。

    这个东西的方案数可以用类似于卡特兰数的公式 $C_i = inom {2i} {i} - inom {2i} {i-1}$ 的推导方法来得到。

    这个请自行搜索,懒得画图了。

    代码

    #pragma GCC optimize("Ofast","inline")
    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=1200005,mod=998244353;
    void Add(int &x,int y){
    	if ((x+=y)>=mod)
    		x-=mod;
    }
    void Del(int &x,int y){
    	if ((x-=y)<0)
    		x+=mod;
    }
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=(LL)x*x%mod)
    		if (y&1)
    			ans=(LL)ans*x%mod;
    	return ans;
    }
    int n;
    int Fac[N],Inv[N];
    void prework(){
    	int n=N-1;
    	for (int i=Fac[0]=1;i<=n;i++)
    		Fac[i]=(LL)Fac[i-1]*i%mod;
    	Inv[n]=Pow(Fac[n],mod-2);
    	Fod(i,n,1)
    		Inv[i-1]=(LL)Inv[i]*i%mod;
    }
    int C(int n,int m){
    	if (m>n||m<0)
    		return 0;
    	return (LL)Fac[n]*Inv[m]%mod*Inv[n-m]%mod;
    }
    int p[N];
    int q[N],head,tail;
    int pos,vis[N];
    int calc(int x,int y){
    	//from (x,y) to (n,n)
    	//without crossing line x=y
    	if (x>n||y>n)
    		return 0;
    	assert(x<=y);
    	int _x=y+1,_y=x-1;
    	return (C(n-x+n-y,n-x)-C(n-_x+n-_y,n-_x)+mod)%mod;
    }
    void Main(){
    	n=read();
    	For(i,1,n)
    		p[i]=read();
    	int ans=0;
    	clr(vis);
    	pos=1,head=tail=0;
    	int Mx=0;
    	int x=0,y=0;
    	For(i,1,n){
    		if (p[i]>Mx){
    			Mx=p[i];
    			while (pos<p[i]){
    				if (!vis[pos]){
    					q[++tail]=pos;
    					vis[pos]=1;
    					y++;
    				}
    				pos++;
    			}
    			Add(ans,calc(x,y+2));
    			x++,y++;
    		}
    		else {
    			Add(ans,calc(x,y+1));
    			if (head>=tail||q[head+1]!=p[i])
    				break;
    			head++;
    			x++;
    		}
    		vis[p[i]]=1;
    	}
    	cout<<ans<<endl;
    }
    int main(){
    	prework();
    	int T=read();
    	while (T--)
    		Main();
    	return 0;
    }
    

      

  • 相关阅读:
    chrome请求cgi遇到net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
    office激活秘钥
    Dynamic 365 中创建编码规则
    D365FO Tool – Automating Start and Stop Environments
    InventReserve on InventTable form button script
    XSLT Transformation XML to JSON D365FO Data Management
    Get started with deployment pipelines
    [Azure DevOps Dynamics] Automate CRM Solution Deployment
    Deploying Web resources or Plugins with Azure DevOps Pipeline
    Deploy and use a continuous build and test automation environment for Dynamics 365
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ394.html
Copyright © 2011-2022 走看看