Increasing Subsequence

时间:2021-07-30
本文章向大家介绍Increasing Subsequence,主要包括Increasing Subsequence使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目大意

给一个排列,问有多少个极大上升子序列,极大是指这个序列不能是其他上升子序列的子序列。

题解

\(f_i\)表示以\(i\)结尾的子序列个数,那么转移的话枚举前面比它小的位置,转移的话这两个位置之间不能有这两个值之间的数。
考虑分治算这个东西,我们分治\((l,mid)\)\((mid+1,r)\)两个区间,计算两个区间之间的贡献,那么我们先去归并这两个序列,在归并的过程中,对于右边序列,我们维护一个位置单调上升的单调栈,左边维护单调下降的单调栈,这样,在右边序列,我们可以利用单调栈找到它前面比它小的最大的元素, 左边的单调栈维护的是合法转移的位置,最后再左边二分出比那个最大的元素大的位置,转移过来即可。

代码

#include<bits/stdc++.h>
#define N 200009
using namespace std;
typedef long long ll;
const int mod=998244353;
int a[N],n,b[N],c[N],pos[N];
int st[N],st1[N],dp[N],dp1[N];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline void MOD(int &x){x=x>=mod?x-mod:x;}
inline void solve(int l,int r){
	if(l==r)return;
	int mid=(l+r)>>1;
	solve(l,mid);
	for(int i=l;i<=mid;++i){
		b[i]=a[i];
	}
	for(int i=mid+1;i<=r;++i){
		c[i]=a[i];
	}
	sort(b+l,b+mid+1);
	sort(c+mid+1,c+r+1);
	int s1=l,s2=mid+1;
	int top1=0,top=0;
	while(s1<=mid&&s2<=r){
		if(b[s1]<c[s2]){
			while(top1&&pos[st1[top1]]<pos[b[s1]])top1--;
			st1[++top1]=b[s1];
			MOD(dp1[top1]=dp1[top1-1]+dp[pos[b[s1]]]);
			s1++;
		}
		else{
		    while(top&&pos[st[top]]>pos[c[s2]])top--;
		    int now=0;
		    if(top)now=st[top];
		    st[++top]=c[s2];
		    int x=max(0ll,upper_bound(st1+1,st1+top1+1,now)-st1-1);
		    MOD(dp[pos[c[s2]]]+=(dp1[top1]-dp1[x]+mod)%mod);
		    s2++;
		}
	}
	while(s2<=r){
		while(top&&pos[st[top]]>pos[c[s2]])top--;
		int now=0;
		if(top)now=st[top];
		st[++top]=c[s2];
		int x=max(0ll,upper_bound(st1+1,st1+top1+1,now)-st1-1);
		MOD(dp[pos[c[s2]]]+=(dp1[top1]-dp1[x]+mod)%mod);
		s2++;
	}
	
	solve(mid+1,r);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        n=rd();
        for(int i=1;i<=n;++i)a[i]=rd(),pos[a[i]]=i;
        int mx=1e9;
        for(int i=1;i<=n;++i){
        	if(pos[i]<mx)dp[pos[i]]=1;
        	else dp[pos[i]]=0;
        	mx=min(mx,pos[i]);
        }
        solve(1,n);
        int ans=0;
		mx=0;
        for(int i=n;i>=1;--i){
        	if(pos[i]>mx)MOD(ans+=dp[pos[i]]);
        	mx=max(mx,pos[i]);
        }
        printf("%lld\n",ans);
    }
  return 0;
}

原文地址:https://www.cnblogs.com/ZH-comld/p/15081176.html