题解:
- n个纸板把矩形分成(n+1)个区域,m个玩具随机仍在里面,求每个区域的玩具的个数,区域编号从0开始到n。
- 二分查找点在哪个位置。如果点P在某条线段AB的左边(A在上面,B在下面),那么PA×PB<0。二分查找最近的线段的左边。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int const N = 5000 + 10;
int n,m,x1,y1,x2,y2;
int sum[N];
typedef struct Point{
int x,y;
}Vector;
Vector up[N],down[N];
int cross(Vector a,Vector b){
return a.x * b.y - a.y * b.x;
}
bool judge(int a,int b,int i){
Vector v1 = (Vector){up[i].x - a,up[i].y - b};
Vector v2 = (Vector){down[i].x - a,down[i].y - b};
return cross(v1,v2) < 0;
}
int solve(int a,int b){
int l = 1, r = n, ans = n+1;
while(l <= r){
int mid = (l + r) >> 1;
if(judge(a,b,mid)){ //如果(a,b)在线段mid的左边
ans = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
return ans - 1;
}
int main(){
while(~scanf("%d",&n) && n){
scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
up[i] = (Point){a,y1};
down[i] = (Point){b,y2};
}
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
sum[solve(a,b)]++;
}
for(int i=0;i<=n;i++)
printf("%d: %d\n",i,sum[i]);
printf("\n");
}
return 0;
}