zoukankan      html  css  js  c++  java
  • AGC039D 题解

    题目描述

    给定在笛卡尔坐标系的单位圆上的(N)个点(圆心为((0, 0)))。第(i)个点的坐标为((cos(frac{2 pi T_i}{L}), sin(frac{2 pi T_i}{L})))

    三个不同的点将在这(N)个点中等概率的随机,请求出这三个点构成的三角形的内切圆圆心的(x)坐标的数学期望和(y)坐标的数学期望。

    约束条件

    (3 leq N leq 3000)

    (N leq L leq 10^9)

    (0 leq T_i leq L - 1)

    (T_i < T_{i+1})

    所有的输入的数都是整数。

    测试点时间限制:4s

    测试点空间限制:1024MB

    题目解答

    算法一

    解题过程

    首先,我们考虑一种内心的刻画方法(这种刻画方法在数学竞赛中被称为"鸡爪定理")。

    ( riangle ABC) 的内心为(I)(AI)( riangle) (ABC)的外接圆交于另一点(M),则(BM = CM = IM)

    证明:由于$ angle BAM = angle CAM(,故) angle BCM = angle CBM(,所以)BM = CM(。又因为)angle IBM = angle CBM + angle IBC = frac{1}{2}(angle CAB + angle ABC) = angle MAB + angle ABI = angle BIM(,所以)BM = MI$

    Alt text

    (之后看这张图的时候(B,C)可能需要互换一下)

    这样,如果我们固定了(B,C)两点,以及(A)(B,C)与圆的哪一段弧上,我们就可以得到弧(BC)的中点(M)(M)(A)(BC)异侧)。我们不能枚举(A)点,但是我们将(I)刻画为:(M + (B - M) cdot e^{i angle AMB})。(解释:((I - M) = (B - M) cdot (cos angle AMB + i sin angle AMB)))(这里我们使用了复平面的工具),那么(M)是固定的,(B - M)是固定的(即与(A)无关)。要求所有(I)的坐标之和,只需要知道(e^{i angle AMB})的和。虽然这个式子与(A,B)有关,但是与(M,C)均无关(圆周角相等)。

    因此,我们先枚举(B),接着逆时针顺序枚举(C),在枚举的过程中顺便维护

    <1>(B)逆时针到(C)的点(A)的数目。

    <2> 对于从(B)逆时针到(C)经过的点(A),维护(e^{i angle AMB})的和(这个和与(M)的位置是无关的)。

    如果我们固定了(B,C)的话,以及(A)(B,C)与圆的哪一段弧上,可以算出(M)的值,也可以算出(M)对答案的贡献的次数。同时,(B - M)对每一个(A)是一样的,而(e^{i angle AMB})的和又是被维护出来的。这样,我们就可以以(O(n^2))的复杂度算出内心的坐标和了。但是,每个内心被算了三次,而且我们最终答案是内心横纵坐标的期望,所以要将答案除以(frac{n(n - 1)(n - 2)}{2})

    算法二

    我们对称地考虑三个弧中点构成的三角形。设这三个点(D,E,F)对应的复数也是(D,E,F),则我们通过计算角度发现内心对于的复数就是(D + E + F)

    证明1:这个三角形的重心为(frac{D + E + F}{3}),并且由欧拉线定理及比例关系容易得到垂心(H = D + E + F)

    证明2: 只需证明(H' = D + E + F)时,((H' - D))((E - F))垂直,而((vec{OE} + vec{OF}) cdot (vec{OF} - vec{OE}) = lvert vec{OF} vert ^2 - lvert vec{OE} vert ^2 = 0),故(D + E + F)( riangle DEF)的垂心。

    得到了这个结论过后,我们枚举两个点,以及它们对应的一段弧,计算出这段弧的中点以及不在这段弧上的点的个数,就可以得到这段弧中点的复数值在最终答案里面出现的次数,再将它们相加即可。

    时间复杂度仍然为(O(n^2))

    代码实现

    
    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 3005;
    const double PI = acos(-1), eps = 1e-10;
    
    int n, L;
    double alpha[N], ansx = 0.0, ansy = 0.0;
    
    double midpoint (double x1, double x2) {
    	double len = x2 - x1;
    	if (len < -eps) len += 2.0 * PI;
    	len /= 2.0;
    	double mid = x1 + len;
    	if (mid >= 2.0 * PI - eps) mid -= 2.0 * PI;
    	return mid;
    }
    
    int main () {
    	scanf("%d%d", &n, &L);
    	for (int i = 0; i < n; i++) {
    		int x;
    		scanf("%d", &x);
    		alpha[i] = 2.0 * PI * x / L;
    	}
    
    	for (int i = 0; i < n; i++) {
    		double nowx = 0.0, nowy = 0.0;
    		for (int j = (i + 1) % n, k = 0; j != i; j = (j + 1) % n, k++) {
    			double m = midpoint(alpha[j], alpha[i]), arg = alpha[j] - alpha[i];
    			double vecx = cos(alpha[i]) - cos(m), vecy = sin(alpha[i]) - sin(m);
    
    			ansx += cos(m) * k, ansy += sin(m) * k;
    			ansx += vecx * nowx - vecy * nowy, ansy += vecx * nowy + vecy * nowx;
    
    			if (arg < -eps) arg += 2.0 * PI;
    			nowx += cos(arg / 2.0), nowy += sin(arg / 2.0);
    		}
    	}
    
    	ansx /= 0.5 * n * (n - 1) * (n - 2), ansy /= 0.5 * n * (n - 1) * (n - 2);
    	printf("%.10lf %.10lf", ansx, ansy);
    	return 0;
    }
    
    
  • 相关阅读:
    期望
    更改开机默认操作系统及等待时间修改
    Python排序
    Python IDLE入门 + Python 电子书
    Python基础教程——1基础知识
    Java:谈谈protected访问权限
    三星I9100有时不能收发彩信完美解决!中国移动
    java继承的权限问题
    Python基础教程——2列表和元组
    访问控制和继承(Java)
  • 原文地址:https://www.cnblogs.com/mathematician/p/12515212.html
Copyright © 2011-2022 走看看