P1493 分梨子
时评作者保持 day 3000 字,
写 blog 算不算表达观点呢?
简要题意:二维平面 n n n 个点,选出最大点集,该集满足:
A × ( x i − m i n x ) + B × ( y i − m i n y ) ≤ C A\times (x_i-minx)+B\times (y_i-miny)\le C A×(xi−minx)+B×(yi−miny)≤C
其中 m i n x = min x i , m i n y = min y i minx=\min x_i,miny=\min y_i minx=minxi,miny=minyi, n ≤ 5000 , x i ≤ 10000 , y i ≤ 10000 n\le 5000,x_i\le 10000,y_i\le 10000 n≤5000,xi≤10000,yi≤10000,ABC在 int 范围内。
30pts:
像这样题目很花的式子,不妨整理与点相关的移至不等号一侧:
A × x i + B × y i ≤ A ⋅ m i n x + B ⋅ m i n y + C A\times x_i+B\times y_i\le A\cdot minx+B\cdot miny+C A×xi+B×yi≤A⋅minx+B⋅miny+C
点集若没确定,minx 和 miny 便不确定,于是可以暴力地枚举 minx,miny,每次扫一遍判断合法点数,复杂度 O ( n 3 ) O(n^3) O(n3),NW上拿到30pts的好成绩。
90pts
我们不关心枚举minx,miny的顺序,因为每组的求解是独立的,这启发我们对上述做法进行优化。二维偏序的典做法。
对 x i x_i xi 小到大排序,首先枚举 x i x_i xi 为 m i n x minx minx,那么 i~n 在 x x x 这一维上均合法, 将 i~n 的 y i y_i yi 再排序,再枚举 y i y_i yi 为 m i n y miny miny,由于 A ⋅ m i n x + B ⋅ m i n y + C A\cdot minx+B\cdot miny+C A⋅minx+B⋅miny+C 单调,尺取即可,枚举 m i n y miny miny 时均摊复杂度 O ( 1 ) O(1) O(1),做法瓶颈在枚举 x i x_i xi 和对 i n i_n in 以 y i y_i yi 关键字排序,复杂度 O ( n 2 log n ) O(n^2\log n) O(n2logn),过掉 n ≤ 2000 n\le 2000 n≤2000,5000 的点大概 3.2 e 8 3.2e8 3.2e8,可以赌一赌阳寿。
100pts
NW设了 n ≤ 5000 n\le 5000 n≤5000 的点很妙,要求复杂度 O ( n 2 ) O(n^2) O(n2).
回到这个式子:
A × x i + B × y i ≤ A ⋅ m i n x + B ⋅ m i n y + C A\times x_i+B\times y_i\le A\cdot minx+B\cdot miny+C A×xi+B×yi≤A⋅minx+B⋅miny+C
暴力做法每一次枚举 m i n x , m i n y minx,miny minx,miny 都要扫一遍点集,注意到式子左侧同样独立——只跟单点有关。仍然暴力枚举 m i n x minx minx,但第二维我们奇想枚举点集,原式便成了关于 m i n y miny miny 的下限,又知道 m i n y miny miny 的上限显然是 y i y_i yi,可以差分每个点符合条件 m i n y miny miny 值域,完了扫一遍即可,复杂度 O ( n 2 ) O(n^2) O(n2) 太妙了。
注意对 m i n y miny miny 的下界大于上界的细节处理。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
int n,ans,t[10005];
LL a,b,c,x[5005],y[5005];
int main(){scanf("%d%d%d%d",&n,&a,&b,&c);rep(i,1,n) scanf("%d%d",x+i,y+i);rep(i,1,n){rep(j,1,n){LL mx=x[i],my=max(0.0,y[j]+ceil(1.0*(a*(x[j]-mx)-c)/b));if(mx<=x[j]&&my<=y[j]) t[my]++,t[y[j]+1]--;}rep(j,0,10001) ans=max(ans,t[j]+=t[j-1]),t[j-1]=0;}printf("%d",ans);
}
又短又精妙呢!