P9181 题解

· · 题解

数学题+二分答案。

题目地址:P9181。

题目简述:

形式化的描述:给定 r_1,r_2,\dots,r_n,且 \sum\limits_{i=1}^n x_i=s,求 S=\dfrac{1}{2}\sum\limits_{i=1}^n x_i\sqrt{r_i^2-x_ i^2} 的最大值。

做法分析:

首先,我们先介绍一下拉格朗日乘数法。

设给定 n 元函数 z=f(x_1,x_2,\dots,x_n) 和附加条件 \varphi(x_1,x_2,\dots,x_n)=0,为寻找 z=f(x_1,x_2,\dots,x_n) 在附加条件下的极值点,先写出拉格朗日函数:F(x_1,x_2,\dots,x_n,\lambda)=f(x_1,x_2,\dots,x_n)+\lambda\varphi(x_1,x_2,\dots,x_n),其中 \lambda 为参数。

接着对 x_1,x_2,\dots,x_n,\lambda 分别求偏导数:

\begin{cases}F'_{x_1}=f'_{x_1}(x_1,x_2,\dots,x_n)+\lambda\varphi'_{x_1}(x_1,x_2,\dots,x_n)\\F'_{x_2}=f'_{x_2}(x_1,x_2,\dots,x_n)+\lambda\varphi'_{x_2}(x_1,x_2,\dots,x_n)\\\dots\\F'_{x_n}=f'_{x_n}(x_1,x_2,\dots,x_n)+\lambda\varphi'_{x_n}(x_1,x_2,\dots,x_n)\\F'_{\lambda}=\varphi_(x_1,x_2,\dots,x_n)\end{cases}

则满足:\begin{cases}F'_{x_1}=0\\F'_{x_2}=0\\\dots\\F'_{x_n}=0\\F'_{\lambda}=0\end{cases}\{x_1,x_2,\dots,x_n\} 即为可能的取等条件。

回到本题,即在约束条件 \varphi(x_1,x_2,\dots,x_n)=\sum\limits_{i=1}^n x_i-s=0 的约束条件下,求 z=f(x_1,x_2,\dots,x_n)=\sum\limits_{i=1}^n x_i\sqrt{r_i^2-x_ i^2} 的最大值,答案即为 \dfrac{1}{2}z_{max}

构造拉格朗日函数:

&=\sum\limits_{i=1}^n x_i\sqrt{r_i^2-x_ i^2}+\lambda(\sum\limits_{i=1}^n x_i-s) \end{aligned}$。 则应该有:$\begin{cases}F'_{x_1}=\dfrac{r_1^2-2x_1^2}{\sqrt{r_1^2-x_1^2}}+\lambda=0\\F'_{x_2}=\dfrac{r_2^2-2x_2^2}{\sqrt{r_2^2-x_2^2}}+\lambda=0\\\dots\\F'_{x_n}=\dfrac{r_n^2-2x_n^2}{\sqrt{r_n^2-x_n^2}}+\lambda=0\\F'_{\lambda}=\sum\limits_{i=1}^n x_i-s=0\end{cases}$。 我们记 $k=-\lambda$,则有: $\dfrac{r_1^2-2x_1^2}{\sqrt{r_1^2-x_1^2}}=\dfrac{r_2^2-2x_2^2}{\sqrt{r_2^2-x_2^2}}=\dots=\dfrac{r_n^2-2x_n^2}{\sqrt{r_n^2-x_n^2}}=k$。 解得: $x_i^2= \dfrac{4r_i^2-k^2-k\sqrt{8r_i^2+k^2}}{8}$。 又 $\dfrac{4r_i^2-k^2-k\sqrt{8r_i^2+k^2}}{8}$ 有可能小于 $0$,此时对应的 $x_i$ 不是实数,此时可设 $x_i=0$,即对 $S$ 的贡献为 $0$(因为不存在满足条件的 $x_i$)。 故: $x_i=\begin{cases}0,\dfrac{4r_i^2-k^2-k\sqrt{8r_i^2+k^2}}{8}<0\\\sqrt{\dfrac{4r_i^2-k^2-k\sqrt{8r_i^2+k^2}}{8}},otherwise\end{cases}$。 最后,对 $k$ 进行二分,找出最小的 $k$,使得 $\sum\limits_{i=1}^n x_i<s$。 最后贴上 AC 代码: ```cpp #include<bits/stdc++.h> #define aa (4*r[i]*r[i]-k*k-k*sqrt(8*r[i]*r[i]+k*k))/8 #define eps 1e-9 long long n; double s; double r[100005]; double calc(double k){//计算面积的两倍 double sum=0; for(int i=1;i<=n;++i){ if(aa<0) continue; sum+=sqrt(aa)*sqrt(r[i]*r[i]-aa); } return sum; } double check(double k){//判断是否满足条件 double len=0; for(int i=1;i<=n;++i){ if(aa<0) continue; len+=sqrt(aa); } if(len>s) return 0; else return 1; } using namespace std; int main(){ scanf("%lld%lf",&n,&s); for(int i=1;i<=n;++i) scanf("%lf",&r[i]); double l,rr,mid; l=0,rr=100000; while(rr-l>eps){//二分 mid=(l+rr)/2; if(check(mid)) rr=mid; else l=mid; } printf("%.10lf",calc(l)/2); return 0; } ```