欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

[XSY3381] 踢罐子(几何)

发布时间:2023/12/3 编程问答 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 [XSY3381] 踢罐子(几何) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

XSY3381

点被选为点对之一的贡献我们单独计算(这部分贡献的总和为4n(n−1)(n−2)4n(n-1)(n-2)4n(n1)(n2))。接下来只讨论剩余部分的贡献。

先把任意三个点构成的六种选择方案合并,发现在外接圆周和弦之间的点每个有2的贡献,在外接圆上的点每个有1的贡献。

然后考虑任意四个点A,B,C,DA,B,C,DA,B,C,D的贡献。
发现当四个点构成凸四边形ABCDABCDABCD
∠A+∠D=180°\angle A+\angle D=180\degreeA+D=180°
A,B,C,DA,B,C,DA,B,C,D四点共圆,即其中一个点在另外三个点构成的三角形的外接圆上,因此A,B,C,DA,B,C,DA,B,C,D四个点每个有1的贡献,A,B,C,DA,B,C,DA,B,C,D四点的贡献为4。

∠A+∠D<180°\angle A+\angle D<180\degreeA+D<180°
则必有∠B+∠C>180°\angle B+\angle C>180\degreeB+C>180°
DDD△ABC\triangle ABCABC的外接圆外,选A,B,CA,B,CA,B,C为点对时,DDD无贡献。同理AAA无贡献。
BBB△ACD\triangle ACDACD的外接圆弧和弦之间,选A,C,DA,C,DA,C,D为点对时,BBB有2的贡献。同理CCC有2的贡献。A,B,C,DA,B,C,DA,B,C,D四点的贡献为4。

∠A+∠D>180°\angle A+\angle D>180\degreeA+D>180°
则必有∠B+∠C<180°\angle B+\angle C<180\degreeB+C<180°。类似上种情况。

四个点构成凹四边形时,易证四个点产生的贡献为0。

因此问题转化为统计凸四边形个数。

给出四个构成凸四边形的点,任选两个点连边,有4种情况剩下两个点在连边同侧,2种情况剩下两个点在连边异侧。

给出四个构成凹四边形的点,任选两个点连边,有3种情况剩下两个点在连边同侧,3种情况剩下两个点在连边异侧。

因此设整张图中有aaa个凸四边形,bbb个凹四边形,
X=∑i<ji,j连边,再无序地选两个点,选的点在连边同侧的方案数X=\sum_{i<j}i,j连边,再无序地选两个点,选的点在连边同侧的方案数X=i<ji,j
Y=∑i<ji,j连边,再无序地选两个点,选的点在连边异侧的方案数Y=\sum_{i<j}i,j连边,再无序地选两个点,选的点在连边异侧的方案数Y=i<ji,j

可列出方程:
{4a+3b=X2a+3b=Y\begin{cases}4a+3b=X\\2a+3b=Y\end{cases}{4a+3b=X2a+3b=Y

解得:

a=X−Y2a=\frac{X-Y}{2}a=2XY

具体实现上,
对于每个点,把剩下的所有点按照和它的连线的斜率排序,求斜率可以用atan2latan2latan2l函数(加上lll避免爆精度)

然后,考虑两个点的连线,设连线两侧的点数分别是LLLRRR(注意这里要判断,不能构成了一个箭头的形状)

选两个点在连线同侧的有(L−1)L+(R−1)R2\frac{(L−1)L+(R−1)R}{2}2(L1)L+(R1)R种情况,选两个点在连线异侧的有L×RL\times RL×R种情况。

时间复杂度O(n2logn)O(n^2logn)O(n2logn)

#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define pi acos(-1) using namespace std; typedef long long ll; const int N=2010; int n,tot; double x[N],y[N],k[N]; ll ans=0; 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; } int main(){n=read();for(int i=1;i<=n;i++){x[i]=read();y[i]=read();}ans=4ll*n*(n-1)*(n-2);for(int i=1;i<=n;i++){tot=0;for(int j=1;j<=n;j++){if(i==j) continue;k[++tot]=atan2l(x[j]-x[i],y[j]-y[i]);if(k[tot]<0) k[tot]+=pi*2;}sort(k+1,k+tot+1);for(int j=1;j<=tot;j++){k[j+tot]=k[j]+pi*2;} for(int j=1,t=1;j<=tot;j++){while(t<=tot*2&&(k[t]<k[j]+pi)) t++;int l=t-j-1;int r=n-1-l-1;ans+=(1ll*l*(l-1)/2+1ll*r*(r-1)/2-1ll*l*r)*2ll;}}printf("%lld\n",ans);return 0; }

总结

以上是生活随笔为你收集整理的[XSY3381] 踢罐子(几何)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。