• [NOI2018]冒泡排序


    题意可以转化成一个点不能既向左又向又移动。

    条件成立当且仅当对于任意一个点,不同时存在左边比它的大点和右边比它小的点,即一个点如果不是前缀最大值就是后缀最小值。

    假设不考虑字典序,有f[i][j]代表考虑前i个点,当前最大值为j的方案数,考虑到如果第i个数如果不填j就只能填所有能填的数中最小的,有转移f[i][j]+=f[i-1][k](k<=j),即f[i][j]=f[i-1][j]+f[i][j-1],发现就是卡特兰数。

    考虑枚举p与q第一个不同的位置i,pi可以填的最小的数为qi的前缀最大值+1,卡特兰数统计一下贡献即可。

    #include<bits/stdc++.h>
    #define file(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
    #define P 998244353
    #define mid (l+r>>1)
    #define N 2100000
    #define M 1300000
    #define lb(x) (x&(-x))
    #define inf 999999999
    #define ll long long
    #define mem(x) memset(x,0,sizeof(x));
    using namespace std;
    int T,n,q[N],mi[N],mn,mx;
    ll ans,fac[N],nfac[N];
    ll C(int x,int y){ return x<y||x<0||y<0?0:fac[x]*nfac[y]%P*nfac[x-y]%P;}
    ll CT(int x,int y){int u=n-y,v=n-x;return (P+C(u+v,u)-C(v+u,u-1))%P;}
    int qpow(ll x,ll y){
    	ll res=1;
    	for(;y;x=x*x%P,y>>=1) if(y&1) res=res*x%P;
    	return res;
    }
    int main(){
    	//freopen("1.txt","r",stdin); 
    	scanf("%d",&T);
    	fac[0]=1;for(int i=1;i<=M;i++) fac[i]=fac[i-1]*i%P;
    	nfac[M]=qpow(fac[M],P-2);for(int i=M-1;~i;i--) nfac[i]=nfac[i+1]*(i+1)%P;
    //	printf("%lld
    ",C(100,20));
    	while(T--){
    		scanf("%d",&n);mn=inf,ans=mx=0;
    		mem(mi);
    		for(int i=1;i<=n;i++) scanf("%d",&q[i]);
    		for(int i=n;i;i--) if(q[i]<mn)mi[i]=1,mn=q[i];
    		for(int i=1;i<=n;i++){
    			mx=max(mx,q[i]);
    	//		printf("%lld
    ",C(i-1,mx+1));
    			(ans+=CT(i-1,mx+1))%=P;
    			if(!mi[i]&&q[i]<mx) break;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    容器适配器————priority_queue
    容器适配器————queue
    容器适配器之总结
    序列式容器之总结
    序列式容器————forward_list
    序列式容器————list
    序列式容器————dequeue
    13.软件项目管理与敏捷方法——如何变更职责笔记
    10.软件项目管理与敏捷方法——沟通管理笔记
    09.软件项目管理与敏捷方法——人力资源管理笔记
  • 原文地址:https://www.cnblogs.com/blogoflyn/p/13269683.html
Copyright © 2020-2023  润新知