• JOI春合宿2014 K 二人の星座


    JOI春合宿2014 K 二人の星座

    链接

    二人の星座

    题意

    平面内有n(n<=3000)个点,有三种颜色,每个点的颜色是三种中的一种,不存在三点一线。求不共用点且不相交的三色三角形对数。

    题解

    两个没有相交的三角形,一定能做出两条公切线,比较类似于两个圆的公切线。
    考虑到这个公切线一定经过两个三角形各一个点,可以枚举这两个点。
    然后用这条线把点分成两边,就能算出被这条公切线分开的三角形有几对了,最后由于每对三角形会被记4次,所以还要除以4。
    然而这样做的话是(O(n^3))的。
    先枚举一个点(i),将剩余点极角排序,就可以用双指针快速统计每条经过点(i)的公切线对答案的贡献了。
    最后效率是(O(n^2logn))

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3e3+10;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    int n; 
    struct P{
    	int x,y;
    	int c,id;
    }a[N<<1];
    P operator - (P x,P y){
    	P z;
    	z.x=x.x-y.x;
    	z.y=x.y-y.y;
    	return z;
    }
    LL cha(P x,P y){
    	return (LL)x.x*y.y-(LL)x.y*y.x;
    }
    bool cmp(P x,P y){
    	return atan2(x.y-a[0].y,x.x-a[0].x)<atan2(y.y-a[0].y,y.x-a[0].x);
    }
    LL ans=0;
    LL L[3],R[3];
    int main(){
    	scanf("%d",&n);
    	for(int i=0;i<n;++i){
    		a[i].x=read();
    		a[i].y=read();
    		a[i].c=read();
    		a[i].id=i+1;
    	}
    	LL A,B,C,D;
    	for(int i=1;i<=n;++i){
    		int j=0;
    		for(int k=0;k<n;++k){
    			if(a[k].id==i){
    				j=k;break;
    			}
    		}
    		if(j) swap(a[0],a[j]);
    		sort(a+1,a+n,cmp);
    		L[1]=L[2]=L[0]=0;R[1]=R[2]=R[0]=0;
    		for(int k=n;k<=n+n-2;++k) a[k]=a[k-n+1];
    		int l=1,r=1;
    		for(int k=1;k<n;++k){
    			if(r<k)r=k;
    			if(l<k)l=k;
    			while(r+2<n+k){
    				++r;
    				++R[a[r].c];
    			}
    			while(l+2<n+k&&cha(a[k]-a[0],a[l+1]-a[0])>0){
    				++l;
    				--R[a[l].c];
    				++L[a[l].c];
    			}
    			if(a[0].c==0){A=L[1]*L[2];B=R[1]*R[2];}
    			else if(a[0].c==1){A=L[0]*L[2];B=R[0]*R[2];}
    			else {A=L[0]*L[1];B=R[0]*R[1];}
    			if(a[k].c==0){C=L[1]*L[2];D=R[1]*R[2];}
    			else if(a[k].c==1){C=L[0]*L[2];D=R[0]*R[2];}
    			else {C=L[0]*L[1];D=R[0]*R[1];}
    			ans+=A*D+B*C;
    			if(cha(a[k]-a[0],a[k+1]-a[0])>0) --L[a[k+1].c];
    			else --R[a[k+1].c];
    		}
    	}
    	ans=ans/(LL)4;
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    day14(JavaDoc)
    day15(Java流程控制)
    day12
    day.6
    day10
    day11(运算符)
    day.5
    proc -x cshell fork()
    I/O -x 标准IO fopen-fclose--fgetc-fputc--fgets-fputs--fwrite-fread--fprintf-fscanf
    I/O -x open()-read()-write()-close()-lseek()
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/13752203.html
Copyright © 2020-2023  润新知