蓝桥杯真题:荒岛探险

纯纯的模拟微积分求面积:

 首先,我们建立一下坐标系,以两个焦点的中心为原点,焦点连成的直线为x轴建立直角坐标系。(答案里边是这么说的,但是代码里边我感觉x轴只是平行这条直线。。。)不过呢,转平行了,我们可以把它们当成x轴和焦点的直线是重合的,因为吧,最后我们微积分求那个小长方形是要用上边界减下边界的,这样就抵消了。。。

我们这样来做,用一条垂直的线从-1000扫到1000,步长是多少呢,取0.001是可以的,假设分割的小长方形,缺失的那一块是正方形的话,一个就是10^-6,最大是2000/0.001*10^-6=2,虽然是2,但是这题确实可以过。

长方形这样来取,能算进面积的必定是有四个焦点的,椭圆两个,三角形里边两个,上顶点,是分别取y的最大值的较小的一个,下顶点,是分别取y的最小值的较大的那个,然后一直加上来就好了。。。。。。

还有一些数学上的知识(这里焦点只是转平行了应该):

 这样去理解就好了。

代码如下所示:

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
double xa, ya, xb, yb, L, A, ans;
double x[6], y[6], Y[6];
double dist(double a, double b, double c, double d){
    return sqrt((c - a) * (c - a) + (d - b) * (d - b));
}
double get(double now, int pos1, int pos2){
    if(fabs(x[pos1] - x[pos2]) <= eps && fabs(x[pos1] - now) <= eps) return inf;
    if(now <= min(x[pos1], x[pos2]) || now >= max(x[pos1], x[pos2])) return inf;
    return (y[pos2] - y[pos1]) / (x[pos2] - x[pos1]) * (now - x[pos2]) + y[pos2];
}
bool ok1(double now){
    double xx = (xa + xb) / 2, yy = (ya + yb) / 2;
    double a = L / 2 , c = dist(xa, ya, xb, yb) / 2;
    double b = sqrt(a * a - c * c);
    double mid = 1.0 - (now - xx) * (now - xx) / (a * a);
    if(mid <= 0) return false;
    mid = sqrt(mid) * b;
    Y[1] = yy - mid, Y[2] = yy + mid;
    return true;
}
bool ok2(double now){
    int cnt = 2;
    for(int i = 1; i <= 3; i++){
        int nex = i + 1 == 4 ? 1 : i + 1;
        double mid = get(now, i, nex);
        if(mid - 1000 > eps) continue;
        if(cnt == 3 && fabs(mid - Y[cnt]) <= eps) continue;
        Y[++cnt] = mid;
    }
    if(cnt != 4) return false;
    return true;
}
double get_angle(double a, double b, double c, double d){
    double now = acos((c - a) / dist(a, b, c, d));
    if(d - b < 0) return 2 * acos(-1) - now;
    return now;
}
void init(){
    A = get_angle(xa , ya , xb , yb);
    double dis1 = dist(0, 0, xa, ya), dis2 = dist(0, 0, xb, yb);
    double S1 = get_angle(0, 0, xa, ya) - A, S2 = get_angle(0, 0, xb, yb) - A;
    xa = dis1 * cos(S1) , ya = dis1 * sin(S1);
    xb = dis2 * cos(S2) , yb = dis2 * sin(S2);
}
void change(int pos){
    double dis = dist(0, 0, x[pos], y[pos]);
    double S = get_angle(0, 0, x[pos], y[pos]) - A;
    x[pos] = dis * cos(S) , y[pos] = dis * sin(S);
}
double calc(double now){
    if(!ok1(now)) return 0;
    if(!ok2(now)) return 0;
    double ma = max(min(Y[1], Y[2]), min(Y[3], Y[4]));
    double mi = min(max(Y[1], Y[2]), max(Y[3], Y[4]));
    if(mi - ma <= eps) return 0;
    return mi - ma;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    cin >> xa >> ya >> xb >> yb >> L;
    init();
    for (int i = 1 ; i <= 3 ; i ++) cin >> x[i] >> y[i] , change(i);
    if(L <= eps || dist(xa, ya, xb, yb) >= L) return cout << "0.00\n" , 0;
    for(double i = -1000 ; i <= 1000 ; i += 0.001) ans += calc(i) * 0.001;
    cout << setprecision(2) << fixed << ans << '\n';
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值