bzoj1071 [SCOI2007]组队

题目链接

problem

给出A,B,C和n个二元组(x,y)。
问最多选多少个二元组使得所选二元组均满足\(A\times (x-minx) + B \times (y - miny) \le C\)。其中\(minx,miny\)分别表示所选二元组中最小的x,y。

solution

将题目中的式子展开得:

\(Ax - Aminx + By - Bminy \le C\)

\(Ax + By \le C + Aminx + Bminy\)

\(s=Ax+By\)。考虑枚举一个minx。然后从小到大枚举一个miny。

将二元组分别按照s和y排序。用一个指针l在按s排序的数组中移动,表示满足\(Ax+By\le C + Aminx + Bminy\)的数量。用一个指针r在按y排序的数组中移动,表示满足\(y \ge miny\)的位置。

因为miny是从小到大枚举的,所以l会不断往右移动,当往右移动一步时,如果跨过位置的y>r所指的位置的y,就将ans++。因为即便当前位置不满足\(y\ge miny\),我们在后面移动r的时候还可以删掉他。然后显然r也是会不断往右移动,移动的过程中,如果发现跨过的位置被统计过答案了,就将ans--。然后就可以不充不漏的统计答案了。

code

/*
* @Author: wxyww
* @Date:   2019-12-14 08:43:08
* @Last Modified time: 2019-12-14 10:21:15
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 5010;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
struct node {
	int h,v; ll w;
}a[N],b[N];
bool cmp1(const node &A,const node &B) {
	return A.w < B.w;
}
bool cmp2(const node &A,const node &B) {
	return A.h < B.h;
}
int main() {
	int n = read();ll A = read(),B = read(),C = read();
	for(int i = 1;i <= n;++i) {
		a[i].h = read(),a[i].v = read();
		a[i].w = a[i].h * A + a[i].v * B;
		b[i] = a[i];
	}

	sort(b + 1,b + n + 1,cmp1);
	sort(a + 1,a + n + 1,cmp2);
	int ans = 0;
	for(int i = 1;i <= n;++i) {
		int minV = a[i].v;int l = 0,r = 0,now = 0;
		for(int j = 1;j <= n;++j) {
			int minH = a[j].h;

			while(b[l + 1].w <= C + A * minH + B * minV && l < n) {
				++l;
				if(b[l].v < minV) continue;
				if(b[l].h > a[r].h) ++now;
			} 
			while(a[r + 1].h < minH && r < n) {
				++r;
				if(a[r].v < minV) continue;
				if(a[r].w <= C + A * minH + B * minV) --now;
			}
			ans = max(ans,now);
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2019-12-14 20:51  wxyww  阅读(121)  评论(0编辑  收藏  举报