题解 [CSP-S 2021] 廊桥分配

传送门

初看暴力非常好打
细看貌似比较套路,处理出数组 \(f[i]\)\(g[i]\) 表示两种位置分别分配 \(i\) 个廊桥时的最大停靠数
然后 \(O(n)\) 合并
发现一个事情是一架飞机如果能在 \(i\) 的情况下产生贡献,也就一定能在 \(i+1\) 的情况下产生贡献(其实假了)
于是尝试维护一个偏移量dlt表示前dlt个廊桥已被占满,然后每次给 \([dlt+1, n]\) 加上1
其实显然假了,因为前面那个结论就是假的连样例都过不去

然后有想过三分,暴力跑了下样例发现不是单峰又跑路了
然后又发现一个性质:\(i\) 的情况能选的飞机一定是 \(i+1\) 能选的飞机的子集
其实正解到这里就显然了,但我想偏了
因为我暴力是差分实现的,所以到这里就觉得 \(i\) 的情况下会有一些时段有些廊桥是空着的,会对 \(i+1\) 造成影响
其实并不会,贪心可以显然证明如果有一架飞机必须在 \(i\) 时刻及以后才能加入,则一定有某一时刻有 \(i\)
可以画图证明所想的情况不成立,即希望会被影响到的飞机其实可以占用标号更小的廊桥
于是枚举廊桥,贪心占满它
可以用一个set维护仍然没有停靠的飞机
复杂度 \(O(nlogn)\)

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 400010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long

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, m1, m2;
int uni[N], usize;
pair<int, int> p1[N], p2[N];

namespace force{
	int ans;
	int op[N];
	int check1(int k) {
		// memset(op, 0, sizeof(op));
		for (int i=0; i<=usize; ++i) op[i]=0;
		int pos=1, cnt=0;
		for (int i=1; i<=usize; ++i) {
			k+=op[i];
			while (pos<=m1 && p1[pos].fir==i) {
				if (k) --k, ++cnt, ++op[p1[pos].sec];
				++pos;
			}
		}
		return cnt;
	}
	int check2(int k) {
		// memset(op, 0, sizeof(op));
		for (int i=0; i<=usize; ++i) op[i]=0;
		int pos=1, cnt=0;
		for (int i=1; i<=usize; ++i) {
			k+=op[i];
			while (pos<=m2 && p2[pos].fir==i) {
				if (k) --k, ++cnt, ++op[p2[pos].sec];
				++pos;
			}
		}
		return cnt;
	}
	void solve() {
		for (int i=0; i<=n; ++i) ans=max(ans, check1(i)+check2(n-i)); //, cout<<check1(i)+check2(n-i)<<' '; cout<<endl;
		// cout<<"f: "; for (int i=1; i<=n; ++i) cout<<check1(i)<<' '; cout<<endl;
		// cout<<"g: "; for (int i=1; i<=n; ++i) cout<<check2(i)<<' '; cout<<endl;
		printf("%d\n", ans);
		exit(0);
	}
}

namespace task1{
	int f[N], g[N], op[N], ans;
	void solve() {
		int dlt, pos;
		dlt=0; pos=1;
		memset(op, 0, sizeof(op));
		for (int i=1; i<=usize; ++i) {
			dlt+=op[i];
			cout<<"i: "<<i<<' '<<dlt<<endl;
			while (pos<=m1 && p1[pos].fir==i) {
				--op[p1[pos].sec];
				cout<<p1[pos].sec<<endl;
				for (int j=dlt+1; j<=n; ++j) ++f[j];
				++dlt; ++pos;
			}
		}
		dlt=0; pos=1;
		memset(op, 0, sizeof(op));
		for (int i=1; i<=usize; ++i) {
			dlt+=op[i];
			while (pos<=m2 && p2[pos].fir==i) {
				--op[p2[pos].sec];
				for (int j=dlt+1; j<=n; ++j) ++g[j];
				++dlt; ++pos;
			}
		}
		cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
		cout<<"g: "; for (int i=1; i<=n; ++i) cout<<g[i]<<' '; cout<<endl;
		for (int i=0; i<=n; ++i) ans=max(ans, f[i]+g[n-i]);
		printf("%d\n", ans);
		exit(0);
	}
}

namespace task{
	int f[N], g[N], ans;
	set<pair<int, int>> s;
	void solve() {
		set<pair<int, int>>::iterator it;
		for (int i=1; i<=m1; ++i) s.insert(p1[i]);
		for (int i=1; i<=n; ++i) if (s.size()) {
			int now=0;
			while ((it=s.upper_bound(make(now, 0)))!=s.end()) {
				++f[i];
				now=it->sec;
				s.erase(it);
			}
			f[i]+=f[i-1];
		}
		s.clear();
		for (int i=1; i<=m2; ++i) s.insert(p2[i]);
		for (int i=1; i<=n; ++i) if (s.size()) {
			int now=0;
			while ((it=s.upper_bound(make(now, 0)))!=s.end()) {
				++g[i];
				now=it->sec;
				s.erase(it);
			}
			g[i]+=g[i-1];
		}
		for (int i=0; i<=n; ++i) ans=max(ans, f[i]+g[n-i]);
		printf("%d\n", ans);
		exit(0);
	}
}

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

	n=read(); m1=read(); m2=read();
	for (int i=1,a,b; i<=m1; ++i) {
		a=read(); b=read();
		p1[i]=make(a, b);
		uni[++usize]=a; uni[++usize]=b;
	}
	for (int i=1,a,b; i<=m2; ++i) {
		a=read(); b=read();
		p2[i]=make(a, b);
		uni[++usize]=a; uni[++usize]=b;
	}
	sort(uni+1, uni+usize+1);
	usize=unique(uni+1, uni+usize+1)-uni-1;
	for (int i=1; i<=m1; ++i) {
		p1[i].fir=lower_bound(uni+1, uni+usize+1, p1[i].fir)-uni;
		p1[i].sec=lower_bound(uni+1, uni+usize+1, p1[i].sec)-uni;
	}
	for (int i=1; i<=m2; ++i) {
		p2[i].fir=lower_bound(uni+1, uni+usize+1, p2[i].fir)-uni;
		p2[i].sec=lower_bound(uni+1, uni+usize+1, p2[i].sec)-uni;
	}
	sort(p1+1, p1+m1+1); sort(p2+1, p2+m2+1);
	// force::solve();
	// task1::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-24 19:32  Administrator-09  阅读(3)  评论(0编辑  收藏  举报