1. 程式人生 > 其它 >CSP-S 2021

CSP-S 2021

我們總是在注意錯過太多,卻不注意自己擁有多少。

T1:
考慮每次飛機獲得的編號機場是固定的。
而是否走上廊道只取決於其的編號機場小於廊道數。
那麼只要考慮計算編號。
那麼可以發現實際上一個二維偏序\(mex\)
考慮一維排序,一維優先佇列,二分BIT \(mex\)

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#define N 100005

int n,m1,m2;

struct P{int l,r,op;}e[N];

bool cmp(P a,P b){return a.l < b.l;}
bool operator < (P a,P b){return a.r > b.r;}

int T[N];

#define lowbit(x) (x & -x)

inline void add(int x,int p){
	for(int i = x;i <= N - 1;i += lowbit(i)){
		T[i] += p;
	}
}

inline int find(int x){
	int ans = 0 ;
	for(int i = x;i;i -= lowbit(i)){
		ans += T[i];
	}	
	return ans;
}

int lasin[N],lasout[N];

std::priority_queue<P>QWQ;
#define mid ((l + r) >> 1)

inline int mex(){
	int l = 1,r = N;
	int ans = 0;
	while(l <= r){
		if(find(mid) != mid)
		ans = mid,r = mid - 1;
		else
		l = mid + 1;
	}
	return ans;
}

inline void del1(){
	std::sort(e + 1,e + m1 + 1,cmp);
	for(int i = 1;i <= m1;++i){
		e[i].op = i;		
		if(QWQ.size())
		while(QWQ.size() && QWQ.top().r < e[i].l )
		add(lasin[QWQ.top().op],-1),QWQ.pop();
		lasin[i] = mex();
		add(lasin[i],1);
		QWQ.push(e[i]);
	}
	std::sort(lasin + 1,lasin + m1 + 1);	
}

inline void del2(){
	for(int i = 1;i <= N;++i)
	T[i] = 0;
	while(QWQ.size())
	QWQ.pop();
	std::sort(e + 1,e + m2 + 1,cmp);
	for(int i = 1;i <= m2;++i){
		e[i].op = i;		
		while(QWQ.size() && QWQ.top().r < e[i].l )
		add(lasout[QWQ.top().op],-1),QWQ.pop();
		lasout[i] = mex();
		add(lasout[i],1);
		QWQ.push(e[i]);
	}
	std::sort(lasout + 1,lasout + m2 + 1);
}

int ans;

inline int Findin(int x){
	int l = 0,r = m1;
	int ans = 0;
	while(l <= r){
		if(lasin[mid] <= x)
		ans = mid,l = mid + 1;
		else
		r = mid - 1;
	}
	return ans;	
} 

inline int Findout(int x){
	int l = 0,r = m2;
	int ans = 0;
	while(l <= r){
		if(lasout[mid] <= x)
		ans = mid,l = mid + 1;
		else
		r = mid - 1;
	}
	return ans;	
} 

int main(){
//	freopen("airport.in","r",stdin);
//	freopen("airport.out","w",stdout);
	scanf("%d%d%d",&n,&m1,&m2);
	for(int i = 1;i <= m1;++i)
	scanf("%d%d",&e[i].l,&e[i].r);
	del1();
	for(int i = 1;i <= m2;++i)
	scanf("%d%d",&e[i].l,&e[i].r);	
	del2();
	for(int i = 0;i <= n;++i){
		int x = i,y = n - i;
		int fx = Findin(x);
		int fy = Findout(y);
		ans = std::max(fx + fy,ans);
	}
	std::cout<<ans<<std::endl;
}

T3
考慮列舉第一次是\(L,R\)
不妨設是 \(L\) ,那麼取出第一位 \(x\) 以及和他顏色相同的另外一位 \(y\)
那麼顯然 \(y\) 一定是最後一次操作的。
那麼可以發現 \(y\) 已經把序列劃分開了,即下列的操作不可以跨越 \(y\) 這個位置。
即下一次操作的 \(y2\) 就是倒數第二次做的,那麼顯然是在劃分開的兩個序列斷點的一側,否則不合法。
考慮維護每次操作劃分序列的左右斷點,以及當前選到哪一個即可。

#include<iostream>
#include<cstdio>
#define ll long long
#define N 500005

int T;
int n;
int a[N << 1];
int pos[N];
int flg;
char ans[N];

inline void dfs(int l,int r,int ql,int qr,int dep){
	if(dep == n){
		for(int i = 0;i < n;++i)
		putchar(ans[i]);
		for(int i = n - 1;i >= 0;--i){
		int now = (ans[i] == 'L' ? -- l : ++ r);
		int tmp = pos[a[now]] - now;
		if(tmp == ql)
		putchar('L'),++ql;
		else
		putchar('R'),--qr;
		}
		flg = 1;					
		puts("");
	}
	int tl = pos[a[l]] - l,tr = pos[a[r]] - r;
	if(tl == ql - 1 && ql - 1 >  l){ans[dep] = 'L';dfs(l + 1,r,ql - 1,qr,dep + 1);return ;}
	else
	if(tl == qr + 1 && qr + 1 <= r){ans[dep] = 'L';dfs(l + 1,r,ql,qr + 1,dep + 1);return ;}
	if(tr == ql - 1 && ql - 1 >= l){ans[dep] = 'R';dfs(l,r - 1,ql - 1,qr,dep + 1);return ;}
	else
	if(tr == qr + 1 && qr + 1 <  r){ans[dep] = 'R';dfs(l,r - 1,ql,qr + 1,dep + 1);return ;}	
}

int main(){
	freopen("palin.in","r",stdin);
	freopen("palin.out","w",stdout);
	scanf("%d",&T);
	while(T -- ){
		scanf("%d",&n);
		for(int i = 1;i <= n;++i)
		pos[i] = 0;
		for(int i = 1;i <= n << 1;++i)
		scanf("%d",&a[i]),pos[a[i]] += i;
		int m = n << 1;
		flg = 0;
		ans[0] = 'L';
		dfs(2,m,pos[a[1]] - 1,pos[a[1]] - 1,1);
		if(flg)continue;
		ans[0] = 'R';		
		dfs(1,m - 1,pos[a[m]] - m,pos[a[m]] - m,1);
		if(flg)continue;
		puts("-1");
	}
}