P1729 计算e 的分治解法
TobyFlenderson · · 题解
计算自然常数
记上式为
拿到
要想使用
(1) 式计算\mathrm{e} 的n 位有效数字,n 应满足10^n<n!
两边取对数,有
于是
int get_n(int d)
{
double f = d * log(10);
double r = 0;
int i = 0;
do
{
i++;
r += log(i);
} while (r < f);
return i;
}
由于高精度除法的消耗很多,可以预测的是,如果直接用
使得原本要调用
void euler_tongfen(int d)
{
int n = get_n(d);
mpz_class p = 1, q = 1; //mpz_class表示高精度整数类
for (int i = n; i > 1; i--)
{
q *= i; //高精度×单精度,时间复杂度为O(n)
p += q;
}
mpf_class r = p; //mpq_class表示高精度浮点数类
r /= q; //高精度除法
++r; //别忘了+1
}
显然上述算法的时间复杂度为
int main()
{
int k;
cin >> k;
tbb::LInt S = 1, P = 1;
int N = get_n(k);
for (int i = N; i > 0; i--)
{
P *= i;
S += P;
}
S <<= k / 4 + 2;
S /= P;
string ans = S.print_str();
const char* out = ans.c_str();
putchar('2'); putchar('.'); putchar('\n');
for (int T = 1; T <= k; ++T) {
putchar(out[T]);
if (T % 50 == 0) putchar('\n');
else if (T % 10 == 0) putchar(' ');
}
return 0;
}
这个链接是我的评测详情,开启了 O2 优化,总用时 O2 则需要
上述代码还有优化的可能:
①对于“高精度×单精度”的算法,它是
②对高精度除法进行优化,这就是另外一个问题了,可以查看P5432 A/B problem的题解。
如何进行分块处理呢?为了方便讨论,记
于是
再令
算法如下图所示
每做一次合并,需要两次乘法,一次加法。显然,若“高精×高精”的算法复杂度仍为
与原算法基本持平,甚至还要稍慢一些。于是只要“高精×高精“的算法复杂度低于
那么只剩下最后一个问题了,阈值的选取,也就是
以下是新的 AC 代码。
int MIN_SPLIT = 128;
static void euler_split(int n, int m, LInt& p, LInt& q)
{
if (m - n < MIN_SPLIT)
{
p = 1;
q = 1;
for (int i = m; i > n; i--)
{
q *= i;
p += q;
}
q *= n;
return;
}
LInt p1, p2, q1, q2;
euler_split(n, (n + m) >> 1, p1, q1);
euler_split((n + m + 2) >> 1, m, p2, q2);
p = p1 * q2 + p2;
q = q1 * q2;
}
int main()
{
int k;
cin >> k;
LInt p, q;
int n = get_n(k);
euler_split(1, n, p, q);
p += q;
p <<= k / 4 + 2;
p /= q;
string ans = p.print_str();
const char* out = ans.c_str();
putchar('2'); putchar('.'); putchar('\n');
for (int T = 1; T <= k; ++T) {
putchar(out[T]);
if (T % 50 == 0) putchar('\n');
else if (T % 10 == 0) putchar(' ');
}
return 0;
}
[1] 朱德凯, 苏岐芳. 多种计算方法下自然常数e的误差和收敛速度比较[J]. 台州学院学报, 2022, 44(03): 11-16. DOI: 10.13853/j.cnki.issn. 1672-3708. 2022. 03. 003.