题解 Sanrd

传送门

  • 要求LIS和LDS无交集什么的:注意如果有交集,二者交集最大为1

尝试过求出一个LIS再删掉这些用过的数,在剩下的数中求LDS
但没有正确性,因为求的这个LIS可能恰好被所有LDS都包含了但存在不被都包含的LIS

于是考虑一个LIS中的数被多少LDS包含了
记包含下标 \(i\) 的 LDS 个数为 \(f_i\),整个序列
的 LDS 个数为 \(tot\),则一个 LIS 不合法,当且仅当所有 LDS 都与它相交
这个 \(f\) 可以树状数组离线下来求(一开始用的线段树+广义扫描线不会改树状数组,后来发现挪线的过程可以直接把这部分的结果离线下来)
于是再求一遍LIS,对每个位置维护任意两个 \(f\) 和不同的LIS即可,因为两个不同的数至少有一个合法

  • 如果要求一组合法解,注意如果有性质使得在每个决策点,两个不同的决策至少有一个合法时可以借此减少决策数
    证明的话,就是两个不同的LIS不可能同时被所有LDS包含
    然后还要注意一点,方案数可能达到 \(2^{\frac{n}{2}}\) 级别,所以要在模大质数意义下考虑
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int p[N], rev[N], lim;
int lis[N], lds[N], top1, top2, lis2[N], lds2[N], ntop1, ntop2;
const ll mod=1e9+7;
bool vis[N];
struct data{int len, pos; data():len(0),pos(0){} inline void build(int a, int b) {len=a; pos=b;}}bit[N];
inline bool operator < (data a, data b) {return a.len<b.len;}
inline bool operator <= (data a, data b) {return a.len<=b.len;}
inline void upd1(int i, data dat) {for (; i<=lim; i+=i&-i) bit[i]=max(bit[i], dat);}
inline data query1(int i) {data ans; for (; i; i-=i&-i) ans=max(ans, bit[i]); return ans;}
inline void upd2(int i, data dat) {for (; i; i-=i&-i) bit[i]=max(bit[i], dat);}
inline data query2(int i) {data ans; for (; i<=lim; i+=i&-i) if (ans<=bit[i]) ans=bit[i]; return ans;}
int lis_len() {
	data len, tem;
	memset(bit, 0, sizeof(bit));
	for (int i=1; i<=n; ++i) {
		tem=query1(p[i]-1);
		++tem.len; tem.pos=i;
		upd1(p[i], tem);
		len=max(len, tem);
	}
	return len.len;
}
int lds_len() {
	data len, tem;
	memset(bit, 0, sizeof(bit));
	for (int i=1; i<=n; ++i) {
		tem=query2(p[i]+1);
		++tem.len; tem.pos=i;
		upd2(p[i], tem);
		len=max(len, tem);
	}
	return len.len;
}
void get_lds() {
	data tem, new2;
	memset(bit, 0, sizeof(bit));
	memset(rev, 0, sizeof(rev));
	for (int i=1; i<=n; ++i) if (!vis[i]) {
		tem=query2(p[i]+1);
		++tem.len; rev[i]=tem.pos; tem.pos=i;
		upd2(p[i], tem);
		new2=max(new2, tem);
	}
	int now=new2.pos;
	do {
		lds[++top2]=now;
		now=rev[now];
	} while (now);
}

namespace task1{
	data len1, len2, new1, new2;
	bool vis1[N], vis2[N];
	void solve() {
		data tem; lim=n+2;
		int now;
		memset(bit, 0, sizeof(bit));
		memset(rev, 0, sizeof(rev));
		for (int i=1; i<=n; ++i) {
			tem=query1(p[i]-1);
			++tem.len; rev[i]=tem.pos; tem.pos=i;
			upd1(p[i], tem);
			len1=max(len1, tem);
		}
		now=len1.pos;
		do {
			lis[++top1]=now;
			vis1[p[now]]=1;
			now=rev[now];
		} while (now);

		memset(bit, 0, sizeof(bit));
		memset(rev, 0, sizeof(rev));
		for (int i=1; i<=n; ++i) {
			tem=query2(p[i]+1);
			++tem.len; rev[i]=tem.pos; tem.pos=i;
			upd2(p[i], tem);
			len2=max(len2, tem);
		}
		now=len2.pos;
		do {
			lds[++top2]=now;
			vis2[p[now]]=1;
			now=rev[now];
		} while (now);
		
		memset(bit, 0, sizeof(bit));
		memset(rev, 0, sizeof(rev));
		for (int i=1; i<=n; ++i) if (!vis1[p[i]]) {
			tem=query2(p[i]+1);
			++tem.len; rev[i]=tem.pos; tem.pos=i;
			upd2(p[i], tem);
			new2=max(new2, tem);
		}
		now=new2.pos;
		do {
			lds2[++ntop2]=now;
			now=rev[now];
		} while (now);
		
		memset(bit, 0, sizeof(bit));
		memset(rev, 0, sizeof(rev));
		for (int i=1; i<=n; ++i) if (!vis2[p[i]]) {
			tem=query1(p[i]-1);
			++tem.len; rev[i]=tem.pos; tem.pos=i;
			upd1(p[i], tem);
			new1=max(new1, tem);
		}
		now=new1.pos;
		do {
			lis2[++ntop1]=now;
			now=rev[now];
		} while (now);
		// cout<<"lis: "; for (int i=1; i<=n; ++i) cout<<lis[i]<<' '; cout<<endl;
		// cout<<"lds: "; for (int i=1; i<=n; ++i) cout<<lds[i]<<' '; cout<<endl;

		if (len1.len==new1.len) {
			// cout<<"pos1"<<endl;
			printf("%d\n", len1.len);
			for (int i=top1; i; --i) printf("%d%c", lis2[i], " \n"[i==1]);
			printf("%d\n", len2.len);
			for (int i=top2; i; --i) printf("%d%c", lds[i], " \n"[i==1]);
		}
		else if (len2.len==new2.len) {
			// cout<<"pos2"<<endl;
			printf("%d\n", len1.len);
			for (int i=top1; i; --i) printf("%d%c", lis[i], " \n"[i==1]);
			printf("%d\n", len2.len);
			for (int i=top2; i; --i) printf("%d%c", lds2[i], " \n"[i==1]);
		}
		else puts("-1");
		exit(0);
	}
}

namespace task{
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define dat(p) dat[p]
	#define pushup(p) dat(p)=dat(p<<1)+dat(p<<1|1)
	int f[N], f2[N], len1, len2, tot;
    struct data{int rev, sum, typ; data():rev(-1),sum(0),typ(0){} data(int a, int b, int c){rev=a; sum=b; typ=c;} inline void build(int a, int b, int c){rev=a; sum=b; typ=c;}}rev[N][2];
	const data nulldat=data(-1, 0, 0);
	inline bool operator != (data a, data b) {return (a.rev!=b.rev)||(a.sum!=b.sum)||(a.typ!=b.typ);}
	inline bool operator == (data a, data b) {return (a.rev==b.rev)&&(a.sum==b.sum)&&(a.typ==b.typ);}
    struct tpl{int len; data fir, sec; tpl():len(0){} tpl(int a, data b, data c){len=a; fir=b; sec=c;}};
	inline bool operator == (tpl a, tpl b) {return a.len==b.len&&a.fir==b.fir&&a.sec==b.sec;}
	inline tpl operator + (tpl a, tpl b) {
		if (a.len==b.len) {
			if (a.fir!=nulldat && a.sec!=nulldat) return a;
			if (b.fir!=nulldat && b.sec!=nulldat) return b;
			if (a.fir.sum!=b.fir.sum) {a.sec=b.fir; return a;}
			// puts("error");
			return a;
		}
		else return a.len>b.len?a:b;
	}
	struct met{int len, cnt; met():len(0),cnt(1){} met(int a, int b) {len=a; cnt=b;} inline void build(int a, int b) {len=a; cnt=b;}};
	inline met operator + (met a, met b) {
		if (a.len && a.len==b.len) return met(a.len, (a.cnt+b.cnt)%mod);
		else return a.len>b.len?a:b;
	}
	struct pre_seg{
		int tl[N<<2], tr[N<<2]; met dat[N<<2];
		void build(int p, int l, int r) {
			tl(p)=l; tr(p)=r;
			if (l==r) return ;
			int mid=(tl(p)+tr(p))>>1;
			build(p<<1, l, mid);
			build(p<<1|1, mid+1, r);
		}
		void upd(int p, int pos, met val) {
			if (tl(p)==tr(p)) {dat(p)=val; return ;}
			int mid=(tl(p)+tr(p))>>1;
			if (pos<=mid) upd(p<<1, pos, val);
			else upd(p<<1|1, pos, val);
			pushup(p);
		}
		void del(int p, int pos) {
			if (tl(p)==tr(p)) {dat(p).build(0, 1); return ;}
			int mid=(tl(p)+tr(p))>>1;
			if (pos<=mid) del(p<<1, pos);
			else del(p<<1|1, pos);
			pushup(p);
		}
		met query(int p, int l, int r) {
			if (l>r) return met(0, 1);
			if (l<=tl(p)&&r>=tr(p)) return dat(p);
			int mid=(tl(p)+tr(p))>>1;
			if (l<=mid&&r>mid) return query(p<<1, l, r)+query(p<<1|1, l, r);
			else if (l<=mid) return query(p<<1, l, r);
			else return query(p<<1|1, l, r);
		}
	}seg1, seg2;
	#if 1
	struct pre_bit{
		met bit[N];
		inline void upd1(int i, met dat) {for (; i; i-=i&-i) bit[i]=bit[i]+dat;}
		inline met query1(int i) {met ans; for (; i<=n; i+=i&-i) ans=ans+bit[i]; return ans;}
		inline void upd2(int i, met dat) {for (; i<=n; i+=i&-i) bit[i]=bit[i]+dat;}
		inline met query2(int i) {met ans; for (; i; i-=i&-i) ans=ans+bit[i]; return ans;}
	}bit1, bit2;
	#endif
	#if 0
	struct seg{
		int tl[N<<2], tr[N<<2]; tpl dat[N<<2];
		void build(int p, int l, int r) {
			tl(p)=l; tr(p)=r;
			if (l==r) return ;
			int mid=(tl(p)+tr(p))>>1;
			build(p<<1, l, mid);
			build(p<<1|1, mid+1, r);
		}
		void upd(int p, int pos, tpl val) {
			if (tl(p)==tr(p)) {dat(p)=val; return ;}
			int mid=(tl(p)+tr(p))>>1;
			if (pos<=mid) upd(p<<1, pos, val);
			else upd(p<<1|1, pos, val);
			pushup(p);
		}
		tpl query(int p, int l, int r) {
			if (l>r) return tpl(0, data(-1, 0, 0), data(-1, 0, 0));
			if (l<=tl(p)&&r>=tr(p)) return dat(p);
			int mid=(tl(p)+tr(p))>>1;
			if (l<=mid&&r>mid) return query(p<<1, l, r)+query(p<<1|1, l, r);
			else if (l<=mid) return query(p<<1, l, r);
			else return query(p<<1|1, l, r);
		}
	}seg;
	#else
	struct bit{
		tpl bin[N];
		bit(){for (int i=1; i<=n; ++i) bin[i]=tpl(0, data(-1, 0, 0), data(-1, 0, 0));}
		inline void upd(int i, tpl dat) {for (; i<=n; i+=i&-i) bin[i]=bin[i]+dat;}
		inline tpl query(int i) {tpl ans(0, data(-1, 0, 0), data(-1, 0, 0)); for (; i; i-=i&-i) ans=ans+bin[i]; return ans;}
	}bit;
	#endif
	void get_lis(data dat) {
		data now=dat;
		while (now.rev>0) {
			lis[++top1]=now.rev;
			// cout<<"rev: "<<now.rev<<' '<<now.typ<<endl;
			vis[now.rev]=1;
			now=rev[now.rev][now.typ];
		}
	}
	void solve() {
		lim=n+2;
		len1=lis_len(); len2=lds_len();
		// cout<<"len: "<<len1<<' '<<len2<<endl;
		met tem, t1, t2;
		#if 0
		seg1.build(1, 1, n); seg2.build(1, 1, n);
		for (int i=n; i; --i) {
			tem=seg2.query(1, 1, p[i]-1);
			// tem=bit2.query2(p[i]-1);
			++tem.len;
			seg2.upd(1, p[i], tem);
			// bit2.upd2(p[i], tem);
			if (tem.len==len2) tot=(tot+tem.cnt)%mod;
		}
		// cout<<"tot: "<<tot<<endl;
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			// t1=seg1.query(1, p[i]+1, n);
			t1=bit1.query1(p[i]+1);
			t2=seg2.query(1, 1, p[i]-1);
			// t2=bit2.query2(p[i]-1);
			// cout<<"t1: "<<t1.len<<' '<<t1.cnt<<endl;
			// cout<<"t2: "<<t2.len<<' '<<t2.cnt<<endl;
			if (t1.len+t2.len+1==len2) f[i]=1ll*t1.cnt*t2.cnt%mod;
			seg2.del(1, p[i]); //++t1.len; seg1.upd(1, p[i], t1);
			++t1.len; bit1.upd1(p[i], t1);
		}
		#else 
		for (int i=n; i; --i) {
			tem=bit2.query2(p[i]-1);
			++tem.len; f[i]=tem.cnt; f2[i]=tem.len;
			bit2.upd2(p[i], tem);
			if (tem.len==len2) tot=(tot+tem.cnt)%mod;
		}
		for (int i=1; i<=n; ++i) {
			t1=bit1.query1(p[i]+1);
			if (t1.len+f2[i]==len2) f[i]=1ll*f[i]*t1.cnt%mod;
			else f[i]=0;
			++t1.len; bit1.upd1(p[i], t1);
		}
		#endif
		// cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
		tpl t, tk;
		// seg.build(1, 1, n);
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			// tk=seg.query(1, 1, p[i]-1);
			t=bit.query(p[i]-1);
			// cout<<"tk: "<<tk.len<<" ("<<tk.fir.rev<<','<<tk.fir.sum<<") ("<<tk.sec.rev<<','<<tk.sec.sum<<") "<<endl;
			// cout<<"t: "<<t.len<<" ("<<t.fir.rev<<','<<t.fir.sum<<") ("<<t.sec.rev<<','<<t.sec.sum<<") "<<endl;
			// assert(tk==t);
			++t.len;
			t.fir.sum=(t.fir.sum+f[i])%mod;
			rev[i][0]=t.fir;
			t.fir.rev=i; t.fir.typ=0;
			if (t.sec!=nulldat) {
				t.sec.sum=(t.sec.sum+f[i])%mod;
				rev[i][1]=t.sec;
				t.sec.rev=i; t.sec.typ=1;
			}
			// seg.upd(1, p[i], t);
			bit.upd(p[i], t);
			if (t.len==len1) {
				if (t.fir!=nulldat) {
					// cout<<"pre_pos1: "<<t.fir.sum<<endl;
					if (t.fir.sum!=tot) {
						// cout<<"pos1"<<endl;
						// cout<<"sum: "<<t.fir.sum<<' '<<tot<<endl;
						get_lis(t.fir);
						get_lds();
						printf("%d\n", len1);
						for (int i=top1; i; --i) printf("%d%c", lis[i], " \n"[i==1]);
						printf("%d\n", len2);
						for (int i=top2; i; --i) printf("%d%c", lds[i], " \n"[i==1]);
						exit(0);
					}
				}
				if (t.sec!=nulldat) {
					// cout<<"pre_pos2: "<<t.sec.sum<<endl;
					if (t.sec.sum!=tot) {
						// cout<<"pos2"<<endl;
						get_lis(t.sec);
						get_lds();
						printf("%d\n", len1);
						for (int i=top1; i; --i) printf("%d%c", lis[i], " \n"[i==1]);
						printf("%d\n", len2);
						for (int i=top2; i; --i) printf("%d%c", lds[i], " \n"[i==1]);
						exit(0);
					}
				}
			}
		}
		puts("-1");
		exit(0);
	}
}

signed main()
{
	freopen("sanrd.in", "r", stdin);
	freopen("sanrd.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) p[i]=read();
	// force::solve();
	// task1::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-12 07:06  Administrator-09  阅读(2)  评论(0编辑  收藏  举报