题解 d

传送门

写出来\(n^2\)就有81pts……
\(n^2\)的话枚举最后成为限制的是哪两个矩形,利用前缀和和二分\(n^3\)\(n^2\)就行了

这题最无脑直接贪心的方法会有后效性
但实际上正解好像就是处理这类问题的一大套路
在两个维度上贪心会有后效性,那选一维枚举,另一维贪心就好了
想了很久也没有想出如何维护\(b_{min}\),题解里说用堆,但用堆我只会\(O(nmlogn)\)复杂度的做法丢人,我暴力都\(O(n^2)\)
思路一直卡在在枚举删\(a_{min}\)的个数时,涉及到在按\(b\)排序的堆中删除\(a\)最小的元素
后来发现不用那么复杂,可以倒序枚举个数,每次加进\(a\)最大的元素
而且堆也没必要每次都清空
发现倒序枚举的实际意义相当于少删一个\(a_{min}\),多删一个\(b_{min}\)
所以维护的时候直接删掉堆里\(b\)最小的,放进去堆外面\(a\)最大的即可

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
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, m;
ll a[N], b[N];

namespace force{
	void solve() {
		ll ans=0, amin=INF, bmin=INF;
		int lim=1<<n;
		for (int s=0,s2,cnt; s<lim; ++s) {
			s2=s; cnt=0; amin=INF, bmin=INF;
			while (s2) {++cnt; s2&=s2-1;}
			if (cnt>m) continue;
			for (int i=0; i<n; ++i) {
				if (!(s&(1<<i))) {
					amin=min(amin, a[i+1]);
					bmin=min(bmin, b[i+1]);
				}
			}
			ans=max(ans, amin*bmin);
		}
		printf("%lld\n", ans);
	}
}

namespace task1{
	void solve() {
		sort(b+1, b+n+1);
		printf("%lld\n", a[1]*b[m+1]);
	}
}

namespace task2{
	void solve() {
		ll amin=INF, bmin=INF;
		for (int i=1; i<=n; ++i) amin=min(amin, a[i]), bmin=min(bmin, b[i]);
		printf("%lld\n", amin*bmin);
	}
}

namespace task3{
	void solve() {
		ll ans=0;
		for (int i=1; i<=n; ++i) ans=max(ans, a[i]*b[i]);
		printf("%lld\n", ans);
	}
}

namespace task4{
	struct rat{ll a, b; inline void build(ll a_, ll b_) {a=a_; b=b_;}}p[N];
	inline bool operator < (rat a, rat b) {return a.a==b.a?a.b<b.b:a.a<b.a;}
	ll b2[N];
	void solve() {
		int tot, dlt; ll ans=0;
		for (int i=1; i<=n; ++i) p[i].build(a[i], b[i]);
		sort(p+1, p+n+1);
		for (int i=1; i<=min(n, m+1); ++i) {
			//cout<<"i: "<<i<<endl;
			tot=0; dlt=i-1;
			for (int j=i+1; j<=n; ++j) if (p[j].b<p[i].b) b2[++tot]=p[j].b;
			sort(b2+1, b2+tot+1);
			if (dlt+tot<=m) ans=max(ans, p[i].a*p[i].b);
			//cout<<"tot: "<<tot<<' '<<dlt<<endl;
			//cout<<"b2: "; for (int j=1; j<=tot; ++j) cout<<b2[j]<<' '; cout<<endl;
			for (int j=i+1,t; j<=n; ++j) {
				t = lower_bound(b2+1, b2+tot+1, p[j].b)-b2-1;
				//cout<<"t: "<<t<<endl;
				if (dlt+t>m) continue;
				else ans=max(ans, p[i].a*min(p[i].b, p[j].b));
				//cout<<"upd: "<<i<<' '<<j<<' '<<p[i].a*min(p[i].b, p[j].b)<<endl;
			}
			//cout<<"ans: "<<ans<<endl<<endl;
		}
		printf("%lld\n", ans);
	}
}

namespace task5{
	struct rat{ll a, b; inline void build(ll a_, ll b_) {a=a_; b=b_;}}p[N];
	inline bool operator < (rat a, rat b) {return a.a==b.a?a.b<b.b:a.a<b.a;}
	struct ele{ll a, b; ele(ll a_, ll b_):a(a_),b(b_){} ele(){}};
	inline bool operator < (ele a, ele b) {return a.b>b.b;}
	priority_queue<ele> q;
	void solve() {
		//if (n==1) {printf("%lld\n", a[1]*b[1]); return ;}
		for (int i=1; i<=n; ++i) p[i].build(a[i], b[i]);
		//for (int i=1; i<=n; ++i) cout<<p[i].a<<','<<p[i].b<<endl;
		sort(p+1, p+n+1);
		ll ans=0, amin=INF, bmin=INF;
		for (int i=0; i<=m; ++i) {
			//cout<<"i: "<<i<<endl;
			amin=INF, bmin=INF;
			for (int j=i+1; j<=n; ++j) q.push(ele(p[j].a, p[j].b));
			for (int j=i+1; j<=m; ++j) q.pop();
			while (!q.empty()) {amin=min(amin, q.top().a); bmin=min(bmin, q.top().b); q.pop();}
			//cout<<"min: "<<amin<<' '<<bmin<<endl;
			ans=max(ans, amin*bmin);
		}
		printf("%lld\n", ans);
	}
}

namespace task{
	struct rat{ll a, b; inline void build(ll a_, ll b_) {a=a_; b=b_;}}p[N];
	inline bool operator < (rat a, rat b) {return a.a==b.a?a.b<b.b:a.a<b.a;}
	priority_queue< int, vector<int>, greater<int> > q;
	void solve() {
		//if (n==1) {printf("%lld\n", a[1]*b[1]); return ;}
		for (int i=1; i<=n; ++i) p[i].build(a[i], b[i]);
		//for (int i=1; i<=n; ++i) cout<<p[i].a<<','<<p[i].b<<endl;
		sort(p+1, p+n+1);
		ll ans=0;
		while (!q.empty()) q.pop();
		for (int i=m+1; i<=n; ++i) q.push(p[i].b);
		for (int i=m+1; i; --i) {
			ans=max(ans, p[i].a*q.top());
			q.pop(); q.push(p[i-1].b);
		}
		printf("%lld\n", ans);
	}
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	int T;
	
	T=read();
	if (!T) return 0;
	while (T--) {
		bool equal=1;
		n=read(); m=read();
		for (int i=1; i<=n; ++i) {
			a[i]=read(), b[i]=read();
			if (i!=1) {if (a[i]!=a[i-1]) equal=0;}
		}
		//if (0&&n<=25) force::solve();
		//else if (!m) task2::solve();
		//else if (equal) task1::solve();
		//else if (m==n-1) task3::solve();
		//else task4::solve();
		task::solve();
	}

	return 0;
}
posted @ 2021-07-23 09:43  Administrator-09  阅读(11)  评论(0编辑  收藏  举报