The 21st Hunan Provincial Collegiate Programming Contest——2025-湖南省赛-B. Cut ellipse(这种题目就是直接这个仿射变换) · znzryb
## 题目大意
**题目描述**
给定二维平面上的一个标准椭圆方程:
$$
\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1
$$
其中 $a$ 和 $b$ 是正实数,分别代表椭圆的半轴。
同时给定平面上的一条直线方程:
$$
y = kx + c
$$
已知该直线一定会将椭圆分割成两个区域,要求计算并输出这两个区域中**面积较大**的那一部分的面积。
**输入格式**
第一行包含两个整数 $a$ 和 $b$($1 \le a,b \le 10^3$),表示椭圆的两个半轴长。
第二行包含两个整数 $k$ 和 $c$($|k|,|c| \le 10^3$),定义了直线 $y = kx + c$。
数据保证直线必定与椭圆相交于两个不同的点。
**输出格式**
输出一个浮点数,表示椭圆中面积较大那一部分的面积。
你的答案与标准答案的绝对误差或相对误差不超过 $10^{-6}$ 即被视为正确。
**样例**
**输入**
```
2 3
1 1
```
**输出**
```
12.709803500
```
**样例解释**
在样例中,给定椭圆方程为 $\frac{x^2}{2^2} + \frac{y^2}{3^2} = 1$,即 $\frac{x^2}{4} + \frac{y^2}{9} = 1$。
给定直线方程为 $y = x + 1$。
**整个椭圆的面积为** $\pi \times a \times b = 6\pi \approx 18.8495559$**。**
直线 $y = x + 1$ 穿过该椭圆将其分成两部分,经过计算,这两部分中面积较大的区域面积约为 $12.709803500$。
## 思路讲解
椭圆方程 $\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1$,做代换 $u = \frac{x}{a},\; v = \frac{y}{b}$,椭圆变成 $u^2 + v^2 = 1$(单位圆)。
直线 $y = kx + c$ 变成 $bv = ka \cdot u + c$,即 $v = \frac{ka}{b}\,u + \frac{c}{b}$。
**面积缩放关系**:这个变换的雅可比行列式是 $ab$,所以在 $(u,v)$ 平面上算出的面积,**乘以** $ab$ **就是椭圆上的面积**。
具体而言,雅克比行列式是:
$$
u = \frac{x}{a}, \quad v = \frac{y}{b}
$$
反过来就是 $x = au,\; y = bv$。雅可比矩阵是把所有偏导数摆成矩阵:
$$
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) = ab - 0 = ab$。
这意味着:$(u,v)$ 平面上任何一块面积为 $S$ 的区域,对应回 $(x,y)$ 平面上面积为 $ab \cdot S$。
```cpp
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](https://codeforces.com/gym/106139/submission/367303278)
::: 源代码
```cpp
/**
* Problem: B. Cut ellipse
* Contest: The 21st Hunan Provincial Collegiate Programming Contest
* Judge: Codeforces
* URL: https://codeforces.com/gym/106139/problem/B
* Created: 2026-03-19 11:41:32
* Author: Gospel_rock
* My blog: https://znzryb.com/
*
* Powered by AutoCp https://github.com/Pushpavel/AutoCp
*/
#include <bits/stdc++.h>
#define all(vec) vec.begin(),vec.end()
#define lson(o) (o<<1)
#define rson(o) (o<<1|1)
#define SZ(a) ((long long) a.size())
#define debug(var) cerr << #var <<" = ["<<var<<"]"<<"\n";
#define debug1d(a) \
cerr << #a << " = ["; \
for (int i = 0; i < (int)(a).size(); i++) \
cerr << (i ? ", " : "") << a[i]; \
cerr << "]\n";
#define debug2d(a) \
cerr << #a << " = [\n"; \
for (int i = 0; i < (int)(a).size(); i++) \
{ \
cerr << " ["; \
for (int j = 0; j < (int)(a[i]).size(); j++) \
cerr << (j ? ", " : "") << a[i][j]; \
cerr << "]\n"; \
} \
cerr << "]\n";
#define cend cerr<<"\n-----------\n"
#define fsp(x) fixed<<setprecision(x)
using namespace std;
using ll = long long;
using ull = unsigned long long;
using DB = long double;
using i128 = __int128;
using CD = complex<double>;
// static constexpr ll MAXN = (ll) 1e6 + 10, INF = (1ll << 61) - 1;
// static constexpr ll mod = 998244353; // (ll)1e9+7;
// static constexpr double eps = 1e-8;
const double pi = acos(-1.0);
ll lT, testcase;
/*
*
*/
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;
if (k1 == 0) {
dis = abs(c1);
} else {
if (c1 == 0) {
dis = 0;
} else {
dis = ((c1 * c1) / k1) * (1.0 / sqrt(c1 * c1 + (c1 * c1) / (k1 * k1)));
dis = abs(dis);
}
}
cout << fsp(10);
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;
#ifdef LOCAL
debug(area);
#endif
area *= a0;
area *= b0;
area = max(area, pi * a0 * b0 - area);
#ifdef LOCAL
debug(area);
debug(shan);
debug(xian);
debug(dis);
#endif
cout << area << "\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef LOCAL
cout.setf(ios::unitbuf); // 无缓冲流,方便我们调试
#endif
// cin >> lT;
// for (testcase = 1; testcase <= lT; ++testcase)
Solve();
return 0;
}
/*
AC
https://codeforces.com/gym/106139/submission/367303278
*/
```
:::
## 心路历程(WA,TLE,MLE……)
这个形式一定要化简到 v=u。。。什么的形式
