微积分相关
拉格朗日乘数法
对于多元函数 \(f(x_1,x_2,\dots,x_n)\),有若 \(m\) 个约束条件形如:\(g_i(x_1,x_2,\dots,x_n)=0\)。
我们要求 \(f\) 在约束条件下的极值。
首先,对与一元情况,我们只要找到所有导数为 \(0\) 的点即可。
对于多元和约束,我们构造函数 \(L(x_1, x_2, \dots , x_n, \lambda)\),\(\lambda\) 是实数:
对于这个函数,我们求出对 \(x_1,x_2,\dots,x_n\) 求出他们的偏微分,要求每个偏微分都等于 \(0\) 并且 \(\lambda\) 的偏微分也是 \(0\)(这样就相当于 \(g\) 为 \(0\))。
即满足方程组:
求出这个方程组的所有解就是可能的极值。
例1: 过河问题:有一条河,分成三段,每段水流速度分别为 \(v_1,v_2,v_3\),宽度分别为 \(w_1, w_2, w_3\),现在要从东岸到西岸,以恒定的速度 \(v\) 过河,要求上岸点和出发地点在同一垂直于河流的直线上,求最少时间。
思路:
显然这个问题中的变量是各段出发的角度,不妨设偏移的角度分别是 \(\theta_1,\theta_2,\theta_3\)。
通过对速度分解,表示过河时间的函数为:
约束为:
于是我们可以用拉格朗日乘数法,引入实数 \(\lambda\),构造函数 \(L(\theta_1,\theta_2,\theta_3,\lambda)\)。
我们考虑对 \(\theta_1,\theta_2,\theta_3,\lambda\) 求偏微分。
首先,求导中有结论:
先对 \(\theta_1\) 求导,显然只有 \(\frac{w_1}{v\cos\theta_1}\) 和 \(\frac{w_1}{v\cos\theta_1}(v_1-v\sin\theta_1)\lambda\) 有影响。
第一个,\(\cos\) 的导数是 \(-\sin\),再根据结论:
第二个,同理:
所以它的偏微分就是:
要求其等于 \(0\),化简就可以得到:
其他同理,我们就可以得到一个方程组,解开就行了。
怎么解还不会,咕咕咕咕。
例2: 平面上有若干个点,距离原点距离分别为 \(r_1,r_2,\dots,r_n\),要求形成凸包面积最大。
思路:
同理,也是以角度为变量,以和为 \(2\pi\) 为约束即可。
最终可以得出方程组,与 \(\lambda\) 有单调性,二分 \(\lambda\) 即可求出答案。
例3: 三位平面上 \(n\) 个点 \((a_1,b_1,c_1),\dots,(a_n,b_n,c_n)\),要求求一条直线 \(L\) 使得投影在这条直线上后所有值的方差最大。
思路:
学了线代再回来做。
例4: CF185B: 给定 \(S, a, b, c \in \mathbb{Z_+}\),求 \(x^ay^bz^c\) 最大值,满足 \(x,y,z \in \mathbb{R_+},0 \le x+y+z \le S\)。
思路:
显然 \(x + y + z = S\) 时最好,构造 \(L(x,y,z,\lambda)=x^ay^bz^c+\lambda(x+y+z-S)\)。
求出偏导可以得到:\(ax^{a-1}y^bz^c=bx^ay^{b-1}z^c=cx^ay^bz^{c-1}\)。
然后求得 \(x:y:z=a:b:c\),于是结合 \(x+y+z-S\) 得到:
就是答案。
思路:
练习拉格朗日乘数法的好题。
为了避免混淆,\(f_i\) 指原题中的 \(v_i'\)。
我们设时间函数 \(f(v_1,v_2,\dots,v_n)=\sum_{i=1}^n\frac{s_i}{v_i}\),总能量为 \(g(v_1,v_2,\dots,v_n)=\sum_{i=1}^nk_{i}(v_i-f_i)^2s_i - E_U\)。
还是构造 \(L(v_1,v_2,\dots,v_n,\lambda)=f(v_1,v_2,\dots,v_n)+\lambda g(v_1,v_2,\dots,v_n)\),然后求偏导。
对 \(x_i\) 求导,将所有与 \(x_i\) 有关的项拎出来:\(\frac{s_i}{v_i}+\lambda k_is_iv_i^2-2\lambda k_is_if_iv_i\)。
求导变成:\(-\frac{s_i}{v_i^2}+2\lambda k_i s_i - 2 \lambda k_i s_i f_i\),我们就是要求这个式子为 \(0\)。
显然可以把 \(s_i\) 除掉,整理变成:
显然 \(v_i \le 0\) 且 \(v_i \le f_i\),左边是个递增的单调函数。
再看对于 \(g\) 的限制不难发现,\(g\) 在 \(v_i \le \max\{0,f_i\}\) 的情况下也是递增的,于是我们可以二分 \(\lambda\),求出每个 \(v_i\) 然后判断。需要两个二分,代码很好写。
例5: 滑行 黑暗爆炸 - 3695
思路:
与例 1 类似,我们可以得到 \(f(\theta_1,\theta_2,\dots,\theta_n)=\sum_{i=1}^n\frac{h_i}{v\cos\theta_i}\) 和 \(g(\theta_1,\theta_2,\dots,\theta_n)=\sum_{i=1}^nh_i\tan\theta_i - X\)。
然后我们依然是对 \(\theta_i\) 求导,注意 \((\tan \theta_i)'=\frac{1}{\cos^2 \theta_i}\),经过整理我们就可以得到:
显然 \(\theta_i\) 应该在 \([0, \frac{\pi}{2})\) 中,即 \(\sin{\theta_i}\) 的值域是 \((-1,0]\),所以我们得到 \(-\frac{1}{v_i} < \lambda \le 0\),去这些左边界的最大值为二分的左边界,不难发现随 \(\lambda\) 增大 \(g\) 会减小,所以依然可以二分来做。
如果直接算可以用三角函数反三角函数,也可以用 \(\sin^2\theta+\cos^2\theta=1\) 求出 \(\cos\),进而求出 \(\tan\),相对来说精度更高,注意开方时要判断是不是负数。
点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
int n, X;
long double h[N] = {0}, v[N] = {0};
long double Sqrt(long double x) {
if (x < 0)
return 0;
return sqrt(x);
}
bool chk(long double x) {
long double sum = 0;
for (int i = 1; i <= n; i++)
sum += 1.0 * h[i] * ((-1.0 * x * v[i]) / Sqrt(1 - x * x * v[i] * v[i]));
return sum >= X;
}
int main() {
cin >> n >> X;
for (int i = 1; i <= n; i++)
cin >> h[i];
long double l = -2e9, r = 0;
for (int i = 1; i <= n; i++)
cin >> v[i], l = max(l, -1.0 / v[i]);
while (l + 1e-15 < r) {
long double mid = (l + r) / 2;
if (chk(mid))
l = mid;
else
r = mid;
}
long double sum = 0;
for (int i = 1; i <= n; i++)
sum += 1.0 * h[i] / (1.0 * v[i] * Sqrt(1 - l * l * v[i] * v[i]));
printf("%.3Lf\n", sum);
return 0;
}
离散微积分
当 \(f(x)\) 是定义在 \(\mathbb{Z}\) 上的函数时,我们定义差分(也就是导数):
离散积分就是:
与微积分基本定理类似。
接着,我们还要知道两个东西。
上阶乘幂:\(x^{\overline{m}}=x(x+1)(x+2)\dots(x+m-1)\)。
下阶乘幂:\(x^{\underline{m}}=x(x-1)(x-2)\dots(x-m+1)\)。
我们对下阶乘幂求离散导数就会得到:
与幂函数求导类似。
运用这个我们还可以得到:
例1: 求出 \(\sum_{0 \le k < n}k^2\) 的封闭形式。
思路:
可以用离散积分来做,有 \(x^2=x^{\underline{2}}+x^{\underline{1}}\),于是我们可以根据积分得出封闭形式。
这种方法可以解决任意次幂。
例2: 证明 \((a+b)^{\underline{n}}=\sum_{r=0}^n\binom{n}{r}a^{\underline{n-r}}b^{\underline{r}}\)
思路:
\(a+b\) 个球中选 \(n\) 个排成一行,double counting.