ZRoi-rectangle题解
题面
Zbox在一个画图板上随便画了一些点, 现在他玩腻了, 于是想擦掉它们.
这个画图板的橡皮擦非常奇怪, 橡皮擦是一个矩形, Zbox只能指定橡皮擦的长宽但无法改变它的面积.
更奇怪的是, 橡皮擦的左上角必须被放在图片的左上角(也就是坐标(0,0)的位置, 这取决于你怎么看这个坐标, 所有点的坐标都是非负的).
这样看来, Zbox并没有办法一次擦掉所有的点了, 他想知道他一次最多能够擦掉多少个点.
思路1
这道题应该是数学+几何题,感觉应该是蓝题难度
我们把黑板看作是一个平面直角坐标系,上面有一些点,如图:
这个橡皮擦的左下角是被固定的,也就是(0,0)点,随着长的变化,宽也会变化,设长为x,宽为y,面积为S,则:
那么黑板擦的右上角就可以形成一个反比例函数,如图:
那么问题就转化为:在反比例函数上选一个点,将其作为矩形的右上角,原点作为左下角,使矩形里的点数量最多。
我们想一下,以E点为例,它能对函数上的那一段区间产生贡献(也就是在右上角在哪一个区间里能把该点擦掉),很显然,画一下图:
E点能产生贡献的区间就是F到H之间,假设E点的坐标为
把所有的点能产生贡献的区间都算出来,如果点的个数为n,那么我们就能得到
n个区间,2n个点,我们把这些点进行离散化,暴力枚举即可
思路2
这个思路就比较难了
感性理解一下,我们橡皮擦的右上角的x坐标肯定是n个点中的一个,因为如果多了一点也不会多擦一个点,这就很贪心
我们用一个树状数组或线段树来维护一个与y轴平行、从左往右移动的扫描线,就完了,
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <cmath>
#include <cstring>
#include <string>
#include <memory.h>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <ctime>
using namespace std;
typedef long long ll;
ll n,S,m;
struct cord{
ll x,y;
}a[500010];
ll s[500010];
ll lowbit(ll x){return x&(-x);}
void update(ll x,ll k)
{
for(ll i=x;i<=m;i+=lowbit(i))
{
s[i]+=k;
}
}
ll query(ll x)
{
ll ret=0;
for(ll i=x;i;i-=lowbit(i)) ret+=s[i];
return ret;
}
bool cmp(cord x,cord y)
{
return x.x==y.x?x.y<y.y:x.x<y.x;
}
int main()
{
scanf("%lld%lld",&n,&S);
for(ll i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
m=max(m,a[i].y);
}
sort(a+1,a+1+n,cmp);
ll ans=0xcfcfcfcfcfcfcfcf;
for(ll i=1;i<=n;i++)
{
update(a[i].y,1);
ans=max(ans,query(min(m,S/a[i].x)));
}
printf("%lld",ans);
return 0;
}