1. 程式人生 > 實用技巧 >【2020五校聯考NOIP #3】序列

【2020五校聯考NOIP #3】序列

題面傳送門
原題題號:Codeforces Gym 101821B

題意:
給出一個排列 \(p\),要你找出一個最長上升子序列(LIS)和一個最長下降子序列(LDS),滿足它們沒有公共元素。或告知無解。
\(1 \leq n \leq 5 \times 10^5\)

wxh 太強辣!wxhtxdy!
首先可以發現一個小性質,那就是原序列任意一個 LIS 和 LDS 至多隻有 \(1\) 個公共元素。
假設它們有 \(2\) 個公共元素 \(p_i,p_j(i<j)\),由於 \(p_i,p_j\) 同時包含在一個 LIS 中,必有 \(p_i<p_j\)。又因為 \(p_i,p_j\)

同時包含在一個 LDS 中,\(p_i>p_j\),矛盾!
我們預處理出 \(f_i\) 表示包含 \(p_i\) 的 LDS 個數,\(sum\) 表示總的 LDS 個數。由於這些數可能很大,我們可以將它模上一個比較大的數。
由於我們只需構造出一組合法的解,我們的目標就是檢驗是否存在一個合法的 LIS,然後順帶著找出原序列扣除掉這個 LIS 後得到的序列 \(p'\) 的一個 LDS
我們考慮不合法的 LIS 長啥樣,假設這個 LIS 為 \([a_{x_1},a_{x_2},\dots,a_{x_l}]\),因為它不合法,所以不存在與它沒有交集的 LDS,也就是所有 LDS 都與它有交集。
而根據之前的性質一個 LIS 和 LDS 至多隻有 \(1\)
個公共元素,故 \(f_{x_1}+f_{x_2}+\dots+f_{x_l}=sum\)
那麼怎樣找這樣一個 LIS 呢?
先用樹狀陣列求出 LIS、LDS 的長度,以及上文提到的 \(f_i,sum\) 的值。
求 LIS 的時候結構體裡另外維護四個值 \(m_1,m_2,p_1,p_2\),表示在滿足上升子序列的長度最大的情況下,兩個不同的 \(f_{x_1}+f_{x_2}+\dots+f_{x_l}\) 的值,以及它們對應的前驅。
如果發現存在一個 LIS 它的 \(f_{x_1}+f_{x_2}+\dots+f_{x_l} \neq sum\),那麼直接跳出輸出就可以了。

/*
Contest: -
Problem: Codeforces Gym 101821 B
Author: tzc_wk
Time: 2020.10.4
*/
#include <bits/stdc++.h>
using namespace std;
#define fi			first
#define se			second
#define pb			push_back
#define fz(i,a,b)	for(int i=a;i<=b;i++)
#define fd(i,a,b)	for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a)		a.begin(),a.end()
#define fill0(a)	memset(a,0,sizeof(a))
#define fill1(a)	memset(a,-1,sizeof(a))
#define fillbig(a)	memset(a,0x3f,sizeof(a))
#define y1			y1010101010101
#define y0			y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
inline int read(){
	int x=0,neg=1;char c=getchar();
	while(!isdigit(c)){
		if(c=='-') neg=-1;
		c=getchar();
	}
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x*neg;
}
const int MOD=23895631;
inline void add(int &x,int v){
	x+=v;if(x>=MOD) x-=MOD;
}
struct numway{
	int val,way;
	numway(int _val=0,int _way=0){val=_val;way=_way;}
	numway operator +(numway x){
		numway z=*this;
		if(x.val>z.val) z.val=x.val,z.way=0;
		if(x.val==z.val) z.way=(z.way+x.way)%MOD;
		return z;
	}
};
int n=read(),a[500005];
struct bit1{
	numway tr[500005];
	inline void clear(){
		for(int i=1;i<=n;i++)
			tr[i].val=tr[i].way=0;
	}
	inline void modify(int x,numway y){
		for(int i=x;i<=n;i+=(i&(-i)))
			tr[i]=tr[i]+y;
	}
	inline numway query(int x){
		numway ans(0,1);
		for(int i=x;i;i-=(i&(-i)))
			ans=ans+tr[i];
		return ans;
	}
} b1;
struct bit2{
	int tr[500005];
	inline void clear(){
		fill0(tr);
	}
	inline void modify(int x,int y){
		for(int i=x;i<=n;i+=(i&(-i)))
			tr[i]=max(tr[i],y);
	}
	inline int query(int x){
		int ans=0;
		for(int i=x;i;i-=(i&(-i)))
			ans=max(ans,tr[i]);
		return ans;
	}
} b2;
int lds_len=0,lis_len=0;
numway lds1[500005],lds2[500005];
int f[500005];
struct event{
	int val,m1,m2,p1,p2;
	event(int _val=0,int _m1=-1,int _m2=-1,int _p1=0,int _p2=0){
		val=_val;m1=_m1;m2=_m2;p1=_p1;p2=_p2;
	}
	friend event operator +(event a,event b){
		if(a.val>b.val) return a;
		if(a.val<b.val) return b;
		if(a.m1==-1) return b;
		else if(a.m2==-1){
			if(b.m1==-1||b.m1==a.m1) a.m2=b.m2,a.p2=b.p2;
			else a.m2=b.m1,a.p2=b.p1;
			return a;
		}
		else return a;
	}
};
struct bit3{
	event tr[500005];
	inline void modify(int x,event v){
		for(int i=x;i<=n;i+=(i&(-i)))
			tr[i]=tr[i]+v;
	}
	inline event query(int x){
		event ans(0,0,-1,0,0);
		for(int i=x;i;i-=(i&(-i)))
			ans=ans+tr[i];
		return ans;
	}
} b3;
event lis[500005];
vector<int> ans_lis,ans_lds;
bool cant[500005];
struct bit4{
	pii tr[500005];
	inline void modify(int x,pii v){
		for(int i=x;i<=n;i+=(i&(-i)))
			tr[i]=max(tr[i],v);
	}
	inline pii query(int x){
		pii ans=make_pair(0,0);
		for(int i=x;i;i-=(i&(-i)))
			ans=max(ans,tr[i]);
		return ans;
	}
} b4;
pii lls[500005];
inline void dump(int x,int y){
	while(x){
		ans_lis.pb(x);cant[x]=1;
		if(lis[x].m1==y){y=(y-f[x]+MOD)%MOD;x=lis[x].p1;}
		else{y=(y-f[x]+MOD)%MOD;x=lis[x].p2;}
	}
	reverse(all(ans_lis));
	printf("%d\n",lis_len);
	foreach(it,ans_lis) printf("%d ",*it);printf("\n");
	for(int i=n;i>=1;i--){
		if(cant[i]) continue;
		lls[i]=b4.query(a[i]-1);
		lls[i].fi++;
		b4.modify(a[i],make_pair(lls[i].fi,i));
	}
	for(int i=1;i<=n;i++){
		if(lls[i].fi==lds_len){
			for(int j=i;j;j=lls[j].se){
				ans_lds.pb(j);
			}
			break;
		}
	}
	printf("%d\n",lds_len);
	foreach(it,ans_lds) printf("%d ",*it);printf("\n");
}
int main(){
	for(int i=1;i<=n;i++) a[i]=read();
	b1.clear();
	for(int i=1;i<=n;i++){
		lds1[i]=b1.query(n-a[i]);lds1[i].val++;
		b1.modify(n-a[i]+1,lds1[i]);lds_len=max(lds1[i].val,lds_len);
	}
	b1.clear();
	for(int i=n;i>=1;i--){
		lds2[i]=b1.query(a[i]-1);lds2[i].val++;
		b1.modify(a[i],lds2[i]);
	}
//	for(int i=1;i<=n;i++) printf("%d %d %d %d\n",lds1[i].val,lds1[i].way,lds2[i].val,lds2[i].way);
	for(int i=1;i<=n;i++){
		if(lds1[i].val+lds2[i].val-1==lds_len){
			f[i]=1ll*lds1[i].way*lds2[i].way%MOD;
		}
//		cout<<f[i]<<endl;
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		if(lds1[i].val==lds_len)
			sum=(sum+lds1[i].way)%MOD;
	}
//	cout<<sum<<endl;
	for(int i=1;i<=n;i++){
		int x=b2.query(a[i]-1);
		b2.modify(a[i],x+1);
		lis_len=max(lis_len,x+1);
	}
	for(int i=1;i<=n;i++){
		lis[i]=b3.query(a[i]-1);
		lis[i].val++;
		if(lis[i].m1!=-1){
			lis[i].m1=(lis[i].m1+f[i])%MOD;
		}
		if(lis[i].m2!=-1){
			lis[i].m2=(lis[i].m2+f[i])%MOD;
		}
//		printf("%d %d %d %d %d\n",lis[i].val,lis[i].m1,lis[i].m2,lis[i].p1,lis[i].p2);
		if(lis[i].val==lis_len){
			if(lis[i].m1!=-1&&lis[i].m1!=sum){
				dump(i,lis[i].m1);return 0;
			}
			if(lis[i].m2!=-1&&lis[i].m2!=sum){
				dump(i,lis[i].m2);return 0;
			}
		}
		b3.modify(a[i],event(lis[i].val,lis[i].m1,lis[i].m2,(lis[i].m1!=-1)?(i):(0),(lis[i].m2!=-1)?(i):(0)));
	}
	printf("IMPOSSIBLE\n");
	return 0;
}