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);
}
又短又精妙呢!