本题有多种解法。仅展示其中几种。不代表题解解法是最佳解法,欢迎评论区补充 qwq
以下参考代码暂仅提供 C++ 代码。
即随机生成足够多的范围内的随机点,判断这个点是否在方程的内部,如果在就是面积的一部分。
注意到本题的方程关于x,y轴对称,为了减少计算负数带来的误差,我们可以只生成第一象限的随机点。(方法二也用到了对称性)
参考代码如下:
#include <bits/stdc++.h>
using namespace std;
const int rands = 10000000;
int cor, n, a, b;
double am, bm;
void mtkl()
{
double rx = rand() / am / a, ry = rand() / bm / b;
double ax = 1, ay = 1;
for (int i = 0; i < n; ++i) //n比较小不开快速幂也可以
ax *= rx, ay *= ry;
if (ax + ay < 1)
++cor;
}
signed main()
{
scanf("%d%d%d", &n, &a, &b);
srand(time(nullptr));
am = 1. * RAND_MAX / a;
bm = 1. * RAND_MAX / b;
for (int i = 0; i < rands; ++i)
mtkl();
printf("%lf", 4. * cor * a * b / rands);
return 0;
}
在范围内等距离划分为许多个密集的小点,判断这些小点是否在方程内。
在本题中,在同等的时间开销下,微分法的精度不如蒙特卡罗法。
为了加速计算,可以使用快速幂。
参考代码如下:
#include <bits/stdc++.h>
int a, b, n, cor, tot;
double as, ae, bs, be, step = 1e-2;
signed main()
{
scanf("%d%d%d", &n, &a, &b);
as = -a, bs = -b, ae = a, be = b;
for (double ai = 0; ai < ae; ai += step)
for (double bi = 0; bi < be; bi += step)
{
double x = ai / a, y = bi / b, ax = 1, ay = 1;
for (int i = n; i; i >>= 1, x *= x, y *= y) //快速幂
if (i & 1)
ax *= x, ay *= y;
if (ax + ay < 1)
++cor;
++tot;
}
printf("%lf", 4. * a * b * cor / tot);
return 0;
}
我们发现,这道题可以直接寻找图形的边界,寻找边界是符合单调性的,所以在微分的过程中,其中一个维度可以使用二分优化。那么每一个长条的小面积可以近似为一个矩形的面积。(在方法二的微分法中是用点来微分,在这里是用小长方形来微分)。
参考代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef double db;
int n, a, b;
db step = 1e-4, s;
inline bool cal(db x, db y)
{
db vx = x / a, vy = y / b, rx = 1, ry = 1;
for (int i = n; i; i >>= 1, vx *= vx, vy *= vy)
if (i & 1)
rx *= vx, ry *= vy;
return rx + ry < 1;
}
signed main()
{
scanf("%d%d%d", &n, &a, &b);
for (db bs = 0.0; bs <= b; bs += step)
{
db left = 0.0, right = a, mid;
while (right - left > 1e-4) //找边界
{
mid = (left + right) / 2;
bool v = cal(mid, bs);
if (v) //点在超椭圆内
left = mid + 1e-5;
else
right = mid - 1e-5;
}
s += mid * step;
}
printf("%lf", 4 * s);
return 0;
}
依然是因为对称,所以只需要计算第一象限。对原方程作变换,得: y=b\times^n\sqrt{1-(\frac{x}{a})^n} 积分得,第一象限的面积表达式为: S=b\int_0^a\ ^n\sqrt{1-(\frac{x}{a})^n} 利用积分的定义法(计算黎曼和,大量小面积),很容易得到答案 qwq。
参考代码:
#include <bits/stdc++.h>
using namespace std;
typedef double db;
db n, a, b, step = 1e-4, s;
signed main()
{
scanf("%lf%lf%lf", &n, &a, &b);
for (db i = 0; i < a; i += step)
s += step * pow(1 - pow(i / a, n), 1 / n);
printf("%lf", s * 4 * b);
return 0;
}
如果你知道 C/C++/Python 自带 \Gamma 函数,可以直接套公式qwq (当然这不是本题出题的本意)
#include <bits/stdc++.h>
signed main()
{
int n, a, b;
scanf("%d%d%d", &n, &a, &b);
double gamma1 = tgamma(1 + 1. / n);
double gamma2 = tgamma(1 + 2. / n);
printf("%lf", 4 * a * b * (gamma1 * gamma1) / gamma2);
return 0;
}