题目大意
题目描述
给定二维平面上的一个标准椭圆方程:
a2x2+b2y2=1
其中 a 和 b 是正实数,分别代表椭圆的半轴。
同时给定平面上的一条直线方程:
y=kx+c
已知该直线一定会将椭圆分割成两个区域,要求计算并输出这两个区域中面积较大的那一部分的面积。
输入格式
第一行包含两个整数 a 和 b(1≤a,b≤103),表示椭圆的两个半轴长。
第二行包含两个整数 k 和 c(∣k∣,∣c∣≤103),定义了直线 y=kx+c。
数据保证直线必定与椭圆相交于两个不同的点。
输出格式
输出一个浮点数,表示椭圆中面积较大那一部分的面积。
你的答案与标准答案的绝对误差或相对误差不超过 10−6 即被视为正确。
样例
输入
输出
样例解释
在样例中,给定椭圆方程为 22x2+32y2=1,即 4x2+9y2=1。
给定直线方程为 y=x+1。
整个椭圆的面积为 π×a×b=6π≈18.8495559。
直线 y=x+1 穿过该椭圆将其分成两部分,经过计算,这两部分中面积较大的区域面积约为 12.709803500。
思路讲解
椭圆方程 a2x2+b2y2=1,做代换 u=ax,v=by,椭圆变成 u2+v2=1(单位圆)。
直线 y=kx+c 变成 bv=ka⋅u+c,即 v=bkau+bc。
面积缩放关系:这个变换的雅可比行列式是 ab,所以在 (u,v) 平面上算出的面积,乘以 ab 就是椭圆上的面积。
具体而言,雅克比行列式是:
u=ax,v=by
反过来就是 x=au,y=bv。雅可比矩阵是把所有偏导数摆成矩阵:
J=(∂u∂x∂u∂y∂v∂x∂v∂y)=(a00b)
雅可比行列式 = det(J)=ab−0=ab。
这意味着:(u,v) 平面上任何一块面积为 S 的区域,对应回 (x,y) 平面上面积为 ab⋅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); 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
源代码
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
#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>;
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
Solve(); return 0; }
|
心路历程(WA,TLE,MLE……)
这个形式一定要化简到 v=u。。。什么的形式
