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;
}
标签:le,二元,miny,移动,bzoj1071,组队,include,Ax,SCOI2007 来源: https://www.cnblogs.com/wxyww/p/bzoj1071.html