A - TOYS POJ - 2318
题意:
一个盒子中有n个隔板,分出n+1个空间(从左往右空间的编号分别是0…n),(隔板之间不会相交,且按照从左往右的顺序给出),现在给你m个坐标的物品,问盒子每个空间内有多少物品
题解:
本质就是判断点在直线的哪一侧
我们设直线为:x+by+c=0
给一个坐标(x0,y0)
如果x0+by0+c = 0说明在直线上(题目数据不可能出现在直线上)
如果x0+by0+c>0,说明点在直线的右侧
如果x0+by0+c<0,说明点在直线的左侧
因为题目给的直线是按照顺序排好的,所谓我们可以二分查找点所在直线的区域
b和c如何得到?看下图推导
代码:
#include<iostream>
#include<string>
#include<queue>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<vector>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=5e3+1;
struct Line{double c,b;/*x+by+c=0;*/
}L[maxn];
int cou[maxn];
int Find(int x,int y,int n){int l=0,r=n+1;while(l<r-1){//找到的点在区间(L[left],L[right])之间 int mid=(l+r)>>1;if(x+L[mid].b*y+L[mid].c>0)//该点在直线的右侧l=mid;else r=mid;}return l;
}
int main()
{int n,m,x1,y1,x2,y2;//n是隔板数量,m是玩具数量 int c=1;while(cin>>n&&n){
// if(c!=1)cout<<endl;
// c++;cin>>m>>x1>>y1>>x2>>y2;memset(cou,0,sizeof(cou));L[0].b=0;L[0].c=0-x1;int u,l;for(int i=1;i<=n;i++){cin>>u>>l;L[i].b=(double)(l-u)/(double)(y1-y2);L[i].c=-1.0*L[i].b*y1-1.0*u;}L[n+1].b=0;L[n+1].c=0-x2;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;int id=Find(x,y,n);cou[id]++;}for(int i=0;i<=n;i++){printf("%d: %d\n",i,cou[i]);}cout<<endl;}return 0;
}