题目大意:
给定一个圆和圆上的一些点,输出这些点组成的锐角三角形的个数。
解题思路:
如果圆上的三个点能组成锐角三角形,那么圆心必在三角形内部,如果圆心在三角形的外部,那么该三角形必为钝角三角形,如果圆心在三角形的边上,那么该三角形必为直角三角形。所以对于圆上的每一个点,作过圆心和该点的一条直线,那么在直线左右两边的点和该点组成的三角形必为钝角三角形或者直角三角形(当圆上有另一个点在直线上),设总数为sum.
注意:上面方法计算到的三角形都被计算了两次!
输出结果为n*(n-1)*(n-2)-sum/2;
代码:
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
#define eps 1e-6
using namespace std;
double angle[20005];
int n,r;
int bs(double a[], int l, int h, double v){ //大于等于v的下标(角度小于等于v的点的个数),
int m;
while ( l < h ){
m = ( l + h ) >> 1;
if (a[m] - v < eps) l=m+1;
else h=m;
}
return l;
}
int serch(double a[],int l, int h,double v){ //角度为v的点是否在该圆上
int m;
while ( l < h ){
m = ( l + h ) >> 1;
if (abs(a[m]-v)<=eps) return m;
if(a[m]<v+eps) l=m+1;
else h=m;
}
return -1;
}
int main(){
int left,right;
int th=1;
while(true){
scanf("%d%d",&n,&r);
if(n==0 && r==0) break;
for(int i=0; i<n; i++){
scanf("%lf",&angle[i]);
}
sort(angle,angle+n);
LL sum=0;
int tmp1,tmp2;
double ang1,ang2;
for(int i=0; i<n; i++){
ang1=angle[i]; //ang1是该点的角度
ang2=ang1-180.00; //ang2是该点对于圆心对称的点的角度
if(ang2<0) ang2+=360.00;
tmp2=bs(angle,0,n,ang2); //圆上角度小于等于v的点的个数
if(tmp2>i){ //i是角度小于该点的点的个数
left=tmp2-i-1;
}
else{
left=i-tmp2;
if(serch(angle,0,n,ang2)!=-1){ //如果有点在该点的对面(关于圆心对称),进行特殊处理
left+=1;
}
}
right=n-1-left;
if(serch(angle,0,n,ang2)!=-1){
right+=1;
}
sum+=(LL)(right*(right-1)/2+(left)*(left-1)/2); //left是直径左边点的个数,
} //right是直径右边点的个数
LL nn=(LL)n; //类型转换,否则下面运算会溢出,这儿卡了几次。
LL all=nn*(nn-1)*(nn-2)/6;
printf("Case %d: ",th++);
printf("%lld\n",all-sum/2);
}
return 0;
}