【AtCoder arc072_f/集训队作业】 Dam

本文解析了一道AtCoder平台上的算法题——水坝问题。通过对题目进行深入分析,提出了一个简洁高效的解决方案。利用单调队列进行等价变换,实现了对注水量和温度的有效管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【AtCoder arc072_f/集训队作业】Dam

所以说思维还是很重要的啊

题意

你有一个初始为空的水坝,每日都会有温度为ti,体积为vi的水流入。为使总水量不超过常数L,你每晚都可以放走一些水,使明日早晨的水可以全部流入。若水的温度不会随时间变化,只会受新流入的水影响,输出1n日中午在水坝是满的的条件下温度的最大值。满足第一天水坝一定会满。

分析

我曾尝试往构造单调队列上想,最后在单调队列上二分答案,但这样在遇到某日温度骤减的情况时难以处理。在观摩了别人的代码后,才意识到这题根本没有那么复杂。
我们断言能把前i天的注水在最优策略下等价变换为i天的注水(表现为单调队列),同时满足:
1.这些天的总注水量为L
2.被注入的水的温度随日期递增。
我们归纳证明:
1.第一日显然可以
2.我们要在i-1’天中选择若干天放水。因为t最大的同时tv也达到最大,而放水的v是确定的,所以放水时t要尽量小,故尽早放水即可(表现为队列pop_front),此时变为i1′′天的注水。
再维护单调性:若第i日注水水温不为当前最大,由贪心可知,第i1′′天不放水一定不比放水劣,意味着我们可以将第i1′′天的注水和第i天的注水合并(表现为pop_back),重复该过程直到第i日注水水温为当前最大,则i天的注水构造完成(push_back)。
根据最优性,将i日的注水混合后的温度即为第i日的答案。

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
#define re_ return
#define in_ inline
#define op_ operator
#define inc(l, i, r) for(i=l; i<r; ++i)
typedef long long ll;
typedef double db;

struct wat
{
    db t; int v;
    wat(): t(0), v(0){}
    wat(db a, int b): t(a), v(b){}
    in_ wat op_+ (wat a)
    {re_ v+a.v? wat((t*v+a.t*a.v)/(v+a.v), v+a.v): wat();}
    in_ wat& op_+= (wat a)
    {re_ *this=*this+a;}
    in_ wat op_- (wat a)
    {re_ v^a.v? wat((t*v-a.t*a.v)/(v-a.v), v-a.v): wat();}
    in_ wat& op_-= (wat a)
    {re_ *this=*this-a;}
    in_ void wr(char* a)
    {printf("(%.6lf, %d)%s", t, v, a);}
};

const int mxn=1<<19;

int n, v0; wat q[mxn];

int main()
{
    int s, t; wat a, b;//b维护水坝中的所有水
//    a.wr("\n");
    scanf("%d%d", &n, &v0);
    for(s=t=0; n--;)
    {
        scanf("%lf%d", &a.t, &a.v);
        for(b+=a; b.v>v0;)//放水
            if(q[s].v<=b.v-v0) b-=q[s++];
            else q[s].v-=b.v-v0, b-=wat(q[s].t, b.v-v0);
        printf("%lf\n", b.t);
        for(;s<t && q[t-1].t>=a.t; a+=q[--t]);//合并所注水
        q[t++]=a;
    }
    re_ 0;
}
<think>好的,我需要帮助用户计算EGE库中`ege_arc`和`ege_circle`的交点坐标。首先,用户给出了两个圆弧和一个圆的参数,我需要先明确这些参数的具体含义。 根据EGE的文档,`ege_arc`函数的参数是`(x, y, width, height, stangle, endangle)`,其中(x,y)是椭圆的外接矩形左上角坐标,width和height是椭圆的宽和高,stangle和endangle是起始和结束角度,单位为度。而`ege_circle`的参数应该是`(x, y, radius)`,即圆心和半径。 用户提供的第一个圆弧参数是`(circle_x - circle_r, circle_y - circle_r/2, 2*circle_r, circle_r, 40, 100)`。这里椭圆的中心应该是在外接矩形的中心,即x + width/2和y + height/2。所以第一个椭圆中心的坐标是: x_arc1 = circle_x - circle_r + (2*circle_r)/2 = circle_x y_arc1 = circle_y - circle_r/2 + circle_r/2 = circle_y 所以椭圆的长半轴a1为width/2=circle_r,短半轴b1为height/2=circle_r/2。这个圆弧的角度范围是40到100度。 第二个圆弧的参数是`(circle_x - circle_r*5/6, circle_y - circle_r*8/27, circle_r*10/6, circle_r*16/27, 17, 146)`。同样计算椭圆中心: x_arc2 = circle_x - (5/6)circle_r + (10/6 circle_r)/2 = circle_x - (5/6)circle_r + (5/6)circle_r = circle_x y_arc2 = circle_y - (8/27)circle_r + (16/27 circle_r)/2 = circle_y - (8/27)circle_r + (8/27)circle_r = circle_y 所以第二个椭圆的长半轴a2是10/6 circle_r /2 = 5/6 circle_r,短半轴b2是16/27 circle_r /2 = 8/27 circle_r。角度范围17到146度。 圆的参数是`(circle_x, circle_y, circle_r * 2/3)`,即圆心在(circle_x, circle_y),半径r=2circle_r/3。 现在的问题转化为:找到椭圆弧与圆的交点,并且这些交点必须位于圆弧的角度范围内。 首先,计算椭圆和圆的交点。椭圆的一般方程是: 对于椭圆1:$\frac{(X - circle_x)^2}{a1^2} + \frac{(Y - circle_y)^2}{b1^2} = 1$,其中a1=circle_r,b1=circle_r/2。 圆方程是:$(X - circle_x)^2 + (Y - circle_y)^2 = (2circle_r/3)^2$。 将椭圆方程代入圆方程: $\frac{(X - circle_x)^2}{a1^2} + \frac{(Y - circle_y)^2}{b1^2} = 1$ → 令A = (X - circle_x),B = (Y - circle_y) 则椭圆方程:A²/a1² + B²/b1² = 1 → B² = b1²(1 - A²/a1²) 代入圆方程:A² + B² = (2circle_r/3)^2 → A² + b1²(1 - A²/a1²) = (2circle_r/3)^2 整理得:A² [1 - b1²/a1²] + b1² = (2circle_r/3)^2 代入a1=circle_r,b1=circle_r/2: A² [1 - ( (circle_r/2)^2 ) / (circle_r)^2 ) ] + (circle_r/2)^2 = (4circle_r²/9) 计算系数: 1 - (circle_r²/4)/(circle_r²) = 1 - 1/4 = 3/4 所以方程变为:A²*(3/4) + circle_r²/4 = 4circle_r²/9 乘以4得:3A² + circle_r² = 16circle_r²/9 移项:3A² = 16circle_r²/9 - circle_r² = (16 - 9)/9 circle_r² → 7circle_r²/9 → A² = 7circle_r²/(9*3) = 7circle_r²/27 → A=±circle_r√(7/27) = ±circle_r*(√21)/9 ≈ ±0.481circle_r 对应的B²= (circle_r/2)^2 (1 - A²/(circle_r)^2) = (circle_r²/4)(1 - 7/27) = (circle_r²/4)(20/27) = 5circle_r²/27 → B=±circle_r√(5/27) = ±circle_r*(√15)/9 ≈ ±0.408circle_r 因此,椭圆1和圆的交点为: (X, Y) = circle_x ± circle_r*(√21)/9, circle_y ± circle_r*(√15)/9 但需要考虑是否在椭圆的圆弧段内。椭圆参数化后的角度θ范围是40到100度。对于椭圆上的点,参数角度θ对应的笛卡尔坐标需要考虑椭圆的方向,可能需要转换为参数方程: 椭圆1的参数方程为: X = circle_x + a1*cosθ Y = circle_y + b1*sinθ 但这里的θ是相对于椭圆的标准参数角,可能和用户给定的起始角度有关。不过,EGE的`ege_arc`使用的是椭圆的外接矩形和起始结束角度,这里的角度是指从椭圆中心向右为0度,逆时针旋转的角度。因此,每个点的角度θ需要满足在40到100度之间。 不过,此时计算得到的交点坐标对应的椭圆上的点是否在40到100度范围内? 例如,对于交点(X1,Y1)=circle_x + a1*cosθ, circle_y + b1*sinθ。这里的θ是相对于椭圆的标准参数角,而用户给定的起始角度可能是指绘制时的起始角度,可能需要进行转换。 但这里可能需要更详细的分析。或者,将椭圆和圆的方程联立解出可能的交点,然后检查这些交点是否在圆弧的角度范围内。 同样的,处理第二个椭圆和圆的交点,步骤类似,但参数不同。 对于椭圆2,a2=5circle_r/6,b2=8circle_r/27。椭圆方程为: $\frac{(X - circle_x)^2}{(5circle_r/6)^2} + \frac{(Y - circle_y)^2}{(8circle_r/27)^2} = 1$ 同样代入圆方程: $(X - circle_x)^2 + (Y - circle_y)^2 = (2circle_r/3)^2$ 联立方程,解出可能的X和Y值。这可能更复杂,需要代数运算。或者,可以用数值方法求解,比如使用牛顿迭代法,但手工计算比较麻烦。 另一种方法是参数化椭圆,然后代入圆的方程求解θ的值,再检查θ是否在给定的角度范围内。例如,椭圆参数化为: X = circle_x + a2*cosθ Y = circle_y + b2*sinθ 代入圆的方程: (a2 cosθ)^2 + (b2 sinθ)^2 = (2circle_r/3)^2 解这个方程得到θ的值,然后检查是否在17到146度之间。 这可能会得到多个解,需要逐一验证。 最后,对于每个可能的交点,还需要判断该点是否在圆弧的实际绘制部分,即角度范围内。 总结步骤: 1. 对于每个椭圆(圆弧)和圆,联立方程求解可能的交点。 2. 对于每个交点,计算其在椭圆上的参数角度θ,判断是否在给定的起始和结束角度范围内。 3. 同样检查该点是否在圆上。 这可能涉及到大量的代数运算,或者需要数值方法。由于手工计算复杂,可能需要编程实现,例如使用数学库(如SymPy)来解方程,或者编写数值求解代码。 不过用户可能希望得到具体的数学步骤或公式,以便在代码中实现。因此,在回答中需要分步骤说明如何计算,并指出可能的难点,例如参数角度的转换、方程求解的复杂性,以及可能需要数值方法等。 此外,还需要注意EGE库中角度的定义是否与标准数学角度一致。例如,EGE的`ege_arc`函数中的角度是否以水平向右为0度,逆时针方向增加,这可能影响参数方程的使用。 最后,用户可能需要将这些数学步骤转换为代码,使用EGE库进行验证或可视化。因此,在回答中建议结合数学推导和编程实现,并可能提供代码框架。</think>### 分步解答 要计算EGE图形库中`ege_arc`和`ege_circle`的交点坐标,需结合解析几何与参数范围验证。以下是具体步骤: --- #### **1. 参数解析** - **圆弧1**:`ege_arc(circle_x - circle_r, circle_y - circle_r/2, 2*circle_r, circle_r, 40, 100)` - 对应椭圆中心:$(x_1, y_1) = (circle_x, circle_y)$ - 长半轴:$a_1 = circle_r$,短半轴:$b_1 = circle_r/2$ - 角度范围:$\theta \in [40^\circ, 100^\circ]$ - **圆弧2**:`ege_arc(circle_x - circle_r*5/6, circle_y - circle_r*8/27, circle_r*10/6, circle_r*16/27, 17, 146)` - 对应椭圆中心:$(x_2, y_2) = (circle_x, circle_y)$ - 长半轴:$a_2 = \frac{5}{6}circle_r$,短半轴:$b_2 = \frac{8}{27}circle_r$ - 角度范围:$\theta \in [17^\circ, 146^\circ]$ - **圆**:`ege_circle(circle_x, circle_y, circle_r * 2/3)` - 方程:$(X - circle_x)^2 + (Y - circle_y)^2 = \left(\frac{2}{3}circle_r\right)^2$ --- #### **2. 椭圆与圆的方程联立** 以**圆弧1**为例: - **椭圆方程**: $$\frac{(X - circle_x)^2}{(circle_r)^2} + \frac{(Y - circle_y)^2}{(circle_r/2)^2} = 1$$ - **圆方程**: $$(X - circle_x)^2 + (Y - circle_y)^2 = \left(\frac{2}{3}circle_r\right)^2$$ 联立两方程,消去$(Y - circle_y)^2$: $$(X - circle_x)^2 = \frac{7}{27}circle_r^2 \quad \Rightarrow \quad X = circle_x \pm \frac{\sqrt{21}}{9}circle_r$$ 代入后得$Y$的解: $$Y = circle_y \pm \frac{\sqrt{15}}{9}circle_r$$ 共4个交点候选点[^1]。 --- #### **3. 验证角度范围** 将交点代入椭圆参数方程,检查角度是否在指定范围内: - **椭圆参数方程**: $$X = circle_x + a_1 \cos\theta, \quad Y = circle_y + b_1 \sin\theta$$ - 解算$\theta$: $$\theta = \arctan\left(\frac{Y - circle_y}{b_1} \div \frac{X - circle_x}{a_1}\right)$$ 若$\theta \in [40^\circ, 100^\circ]$,则为有效交点。 --- #### **4. 代码实现框架** ```cpp #include <ege.h> #include <cmath> void find_intersection(float circle_x, float circle_y, float circle_r) { // 计算圆弧1与圆的交点 float a1 = circle_r; float b1 = circle_r / 2; float delta_x = sqrt(7.0f/27) * circle_r; float delta_y = sqrt(15.0f/27) * circle_r; // 候选交点 std::vector<std::pair<float, float>> candidates = { {circle_x + delta_x, circle_y + delta_y}, {circle_x + delta_x, circle_y - delta_y}, {circle_x - delta_x, circle_y + delta_y}, {circle_x - delta_x, circle_y - delta_y} }; // 验证角度范围 for (auto& pt : candidates) { float theta = atan2((pt.second - circle_y) / b1, (pt.first - circle_x) / a1); theta = theta * 180 / M_PI; // 转换为角度 if (theta >= 40 && theta <= 100) { // 输出有效交点 ege_circle(pt.first, pt.second, 3); // 标记交点 } } } ``` --- #### **注意事项** 1. **椭圆参数角与实际绘制角**:EGE的`ege_arc`角度以水平右方向为$0^\circ$,逆时针增加,需直接使用此定义计算。 2. **数值精度问题**:浮点运算可能存在误差,需设置合理容差(如角度误差±0.1°)。 3. **多交点处理**:椭圆与圆最多有4个交点,需逐一验证。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值