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");
	}
}

T2
不说了吧。
太痛苦了。
我现在写都觉得痛苦。
我再用记忆化搜索写区间dp我是傻逼我是.

#include<iostream>
#include<cstdio>
#define ll long long 
#define N 505
#define mod ((ll)1e9 + 7)

ll f[N][N];
ll g[N][N];
ll x[N][N];
int nex[N];
int n,k;
char s[N];

int main(){
	scanf("%d%d",&n,&k);
	scanf("%s",s + 1);
	for(int l = 1;l <= n;++l){
		if(s[l] != '?' && s[l] != '*')continue;
		x[l][l] = 1;
		for(int r = l + 1;r <= n;++r){
			if(s[r] != '?' && s[r] != '*')break;
			x[l][r] = 1;
		}
	}
	for(int len = 2;len <= n;++len){
		int r;
		for(int l = 1;l + len - 1 <= n;++l){
			r = l + len - 1;
			f[l][r] = g[l][r] = 0;
			if((s[l] != '(' && s[l] != '?') || (s[r] != ')' && s[r] != '?'))
			continue;
			if(l + 1 == r){
				f[l][r] = (f[l][r] + 1) % mod;
				continue;
			}
			if(len - 2 <= k && x[l + 1][r - 1])
			f[l][r] = (f[l][r] + 1) % mod;
			f[l][r] = (f[l][r] + f[l + 1][r - 1] + g[l + 1][r - 1]) % mod;
			for(int li = l + 1;li <= std::min(r - 2,l + k);++li)
			if(x[l + 1][li])
			f[l][r] = (f[l][r] + f[li + 1][r - 1] + g[li + 1][r - 1]) % mod;
			for(int ri = r - 1;ri >= std::max(l + 2,r - k);--ri)
			if(x[ri][r - 1])
			f[l][r] = (f[l][r] + f[l + 1][ri - 1] + g[l + 1][ri - 1]) % mod;
			//(....)
			int op = 0;
			for(int i = l + 1;i <= r - 2;++i){
				if(op <= i)op = i + 1;
				while((s[op] == '*' || s[op] == '?') && op < r - 1)op ++ ;
				nex[i] = std::min(i + k + 1,op);
			}//del_longest_***
			ll sum = 0;
			for(int j = l + 2;j <= nex[l + 1];++j)
			sum = (sum + f[j][r]) % mod;
			g[l][r] = (g[l][r] + (f[l][l + 1] + g[l][l + 1]) % mod * sum % mod) % mod;
			for(int i = l + 2;i <= r - 2;++i){
				sum = (sum - f[i][r] + mod) % mod;
				for(int j = nex[i - 1] + 1;j <= nex[i];++j)
				sum = (sum + f[j][r]) % mod;
				g[l][r] = (g[l][r] + (f[l][i] + g[l][i]) % mod * sum % mod) % mod;
			}
			//()....()
//			std::cout<<l<<" "<<r<<" "<<f[l][r]<<" "<<g[l][r]<<std::endl;
		}
	}
	std::cout<<(f[1][n] + g[1][n]) % mod<<std::endl;
}
posted @ 2021-10-26 15:10  fhq_treap  阅读(115)  评论(0)    收藏  举报