0%

The 21st Hunan Provincial Collegiate Programming Contest——2025-湖南省赛-B. Cut ellipse(这种题目就是直接这个仿射变换)

题目大意

题目描述
给定二维平面上的一个标准椭圆方程:

x2a2+y2b2=1\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1

其中 aabb 是正实数,分别代表椭圆的半轴。

同时给定平面上的一条直线方程:

y=kx+c y = kx + c

已知该直线一定会将椭圆分割成两个区域,要求计算并输出这两个区域中面积较大的那一部分的面积。

输入格式
第一行包含两个整数 aabb1a,b1031 \le a,b \le 10^3),表示椭圆的两个半轴长。
第二行包含两个整数 kkcck,c103|k|,|c| \le 10^3),定义了直线 y=kx+cy = kx + c
数据保证直线必定与椭圆相交于两个不同的点。

输出格式
输出一个浮点数,表示椭圆中面积较大那一部分的面积。
你的答案与标准答案的绝对误差或相对误差不超过 10610^{-6} 即被视为正确。

样例

输入

1
2
2 3
1 1

输出

1
12.709803500

样例解释
在样例中,给定椭圆方程为 x222+y232=1\frac{x^2}{2^2} + \frac{y^2}{3^2} = 1,即 x24+y29=1\frac{x^2}{4} + \frac{y^2}{9} = 1
给定直线方程为 y=x+1y = x + 1
整个椭圆的面积为 π×a×b=6π18.8495559\pi \times a \times b = 6\pi \approx 18.8495559
直线 y=x+1y = x + 1 穿过该椭圆将其分成两部分,经过计算,这两部分中面积较大的区域面积约为 12.70980350012.709803500

思路讲解

椭圆方程 x2a2+y2b2=1\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1,做代换 u=xa,  v=ybu = \frac{x}{a},\; v = \frac{y}{b},椭圆变成 u2+v2=1u^2 + v^2 = 1(单位圆)。

直线 y=kx+cy = kx + c 变成 bv=kau+cbv = ka \cdot u + c,即 v=kabu+cbv = \frac{ka}{b}\,u + \frac{c}{b}

面积缩放关系:这个变换的雅可比行列式是 abab,所以在 (u,v)(u,v) 平面上算出的面积,乘以 abab 就是椭圆上的面积

具体而言,雅克比行列式是:

u=xa,v=ybu = \frac{x}{a}, \quad v = \frac{y}{b}

反过来就是 x=au,  y=bvx = au,\; y = bv。雅可比矩阵是把所有偏导数摆成矩阵:

J=(xuxvyuyv)=(a00b)J = \begin{pmatrix} \frac{\partial x}{\partial u} & \frac{\partial x}{\partial v} \\ \frac{\partial y}{\partial u} & \frac{\partial y}{\partial v} \end{pmatrix} = \begin{pmatrix} a & 0 \\ 0 & b \end{pmatrix}

雅可比行列式 = det(J)=ab0=ab\det(J) = ab - 0 = ab

这意味着:(u,v)(u,v) 平面上任何一块面积为 SS 的区域,对应回 (x,y)(x,y) 平面上面积为 abSab \cdot S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Solve() {
ll a0, b0, k0, c0;
cin >> a0 >> b0 >> k0 >> c0;
DB k1 = (DB) (k0 * a0) / b0;
DB c1 = c0 / DB(b0);
DB dis = distancePL(Point(0, 0), Line(k1, c1));
cout << fsp(10);
// 这个 dis = 0 的特判其实不需要
if (dis == 0) {
DB area = pi * a0 * b0;
area /= 2;
cout << area << "\n";
return;
}
// 弦长
DB xian = 2 * sqrt(1 - dis * dis);
// 角度大小
DB angle = 2 * acos(dis / 1);
DB shan = (angle / (2 * pi)) * pi;
DB area = shan - 0.5 * dis * xian;

area *= a0;
area *= b0;
area = max(area, pi * a0 * b0 - area);

cout << area << "\n";
}

AC代码

AC
https://codeforces.com/gym/106139/submission/367303278

心路历程(WA,TLE,MLE……)

这个形式一定要化简到 v=u。。。什么的形式

image