Problem A: 踢罐子 解题报告
Problem A: 踢罐子
Description
平面上有\(n\)个点,其中任意2点不重合,任意3点不共线。
我们等概率地选取一个点A,再在剩下的\(n-1\)个点中等概率地选取一个点B,再在剩下的\(n-2\)个点中等概率地选取一个点C。
然后我们计算伤害倍率\(d\)。作ABC外接圆,每一个位于弧BC和线段BC之间的点计1倍,每一个位于弧BC上的点(包括B,C两点)计1/2倍,特别的,点A计1倍。将这些倍率全部加起来得到伤害倍率\(d\)。
注意:弧BC是指,ABC外接圆上B到C而不包含点A的部分,这个弧不一定是劣弧。
给定这\(n\)个点的坐标,你需要求出\(d\)的期望。为了简单起见,你只需要输出\(d\times n\times (n-1)\times (n-2)\times 2\)的值,可以看出这是一个整数。
Input
第一行一个正整数\(n\)
接下来\(n\)行,每行2个整数\(x, y\),空格分隔,表示一个坐标。
Output
仅一行,一个数,表示\(d\times n\times (n-1)\times (n-2)\times 2\)的值。
HINT
对于40%的数据,n<=20。
对于60%的数据,n<=50。
对于80%的数据,n<=200。
对于100%的数据,3<=n<=1000。
对于100%的数据,xi和yi的绝对值不超过2000000000。
暴力需要求圆心,最后选择了列圆的方程高斯消元解的诡异办法,wjyyy神仙给出了一个向量的做法还没仔细看...
事实上这个题感觉思路不太自然。
先把处于顶点的贡献算好是\(4n(n-1)(n-2)\)。
然后四个点四个点讨论
发现如果四个点是凸边形,那么这四个点贡献8,否则不产生贡献。
问题转化成统计凸四边形个数了。
凸四边形两两连边后有4条边剩下两个点在异侧,2条边同侧
而凹的3异3同
可以先统计X个异侧,Y个同侧,然后列方程解凸四边形个数
统计的时候枚举一个点,然后极角排序另一个就可以了。
Code:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define ll long long
const int N=2010;
const double pi=acos(-1);
int n,tot;ll X,Y;
double dx[N],dy[N],s[N];
ll cal(ll x){return x*(x-1)/2;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf%lf",dx+i,dy+i);
for(int i=1;i<=n;i++)
{
tot=0;
for(int j=1;j<=n;j++)
{
if(i!=j)
{
s[++tot]=atan2(dy[j]-dy[i],dx[j]-dx[i]);
if(s[tot]<0) s[tot]+=pi*2;
}
}
std::sort(s+1,s+1+tot);
for(int j=1;j<=tot;j++) s[j+tot]=s[j]+2*pi;
for(int j=1,k=1;j<=tot;j++)
{
while(k<=tot*2&&s[k]-s[j]<=pi) ++k;
int c1=k-j-1,c2=n-c1-2;
X+=1ll*c1*c2;//异
Y+=cal(c1)+cal(c2);//同
}
}
printf("%lld\n",(Y-X)*2+4ll*n*(n-1)*(n-2));
return 0;
}
2018.12.31