容斥原理(二分+排序)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4155

题目大意:寻找两个圆的交集部分的点的个数c1,之后再寻找圆外面的点的个数c2。如果c2<c1则输出0,否则输出c2-c1

解题思路:

这个题目如果纯粹的暴力肯定是超时(别尝试了,我已经暴了N遍了,还是TLE)。关键还是优化算法,利用容斥原理+二分+排序

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
#include<iostream>
#define maxn 200000+10
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
int v[maxn][2];
double d1[maxn],d2[maxn];//保存每个点到两个圆的圆心的距离
int bs(double s[],int l,int h,int v)//二分查找,找出在圆内有多少个点
{
    while(l<h)
    {
        int m=(l+h)>>1;
        if(s[m]<=v)
        {
            l=m+1;
        }
        else
        {
            h=m;
        }
    }
    return l;
}
int main()
{
    int t,ncase=1;
    while(scanf("%d",&t)&&t)
    {
        printf("Case %d:\n",ncase++);
        for(int i=0;i<t;i++)
        {
            scanf("%d%d",&v[i][0],&v[i][1]);
        }
        int x1,y1,x2,y2,q;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&q);
        for(int i=0;i<t;i++)
        {
            d1[i]=(double)sqrt((v[i][0]-x1)*(v[i][0]-x1)+(v[i][1]-y1)*(v[i][1]-y1));
            d2[i]=(double)sqrt((v[i][0]-x2)*(v[i][0]-x2)+(v[i][1]-y2)*(v[i][1]-y2));
        }
        sort(d1,d1+t);
        sort(d2,d2+t);
        int c1,c2;
        while(q--)
        {
            double a,b;
            scanf("%lf%lf",&a,&b);
            c1=bs(d1,0,t-1,a);//printf("c1=%d\n",c1);
            c2=bs(d2,0,t-1,b);//printf("c2=%d\n",c2);
            if(t-c1-c2<=0)
                printf("0\n");
            else
                printf("%d\n",t-c1-c2);
        }
    }
    return 0;
}


你可能感兴趣的:(容斥原理(二分+排序))