📅  最后修改于: 2023-12-03 15:28:48.026000             🧑  作者: Mango
本题为 "门|门 IT 2005" 比赛的第 67 题。本题需要使用高精度计算,求出指定的数值问题的答案。
给定两个正整数 $n, m$,其中 $n$ 为位数比较大的数,$m$ 为 1 或 2,根据 $m$ 的不同,求出以下两种数值问题的答案:
$A=\sum_{i=1}^n \frac{1}{i}$,保留小数点后 $n$ 位数字。若小数点后第 $n+1$ 位数字为 $5$,则向下舍入。
$B=\prod_{i=1}^n {\frac{(i^2+1)}{i^2}}$,保留小数点后 $n$ 位数字。若小数点后第 $n+1$ 位数字为 $5$,则向下舍入。
输入文件的第一行包含两个正整数 $n$ 和 $m$,分别表示题目描述中给定的两个正整数。
对于第一种数值问题,输出一个保留小数点后 $n$ 位的实数,保留答案小数位末尾的 $0$。若答案的 $n+1$ 位数字为 $5$,则向下舍入。
对于第二种数值问题,输出一个保留小数点后 $n$ 位的实数,保留答案小数位末尾的 $0$。若答案的 $n+1$ 位数字为 $5$,则向下舍入。
5 1
2.28333
在第一种数值问题中,我们需要计算如下的数值:
$$ A=\sum_{i=1}^n \frac{1}{i} $$
直接计算这个式子是不可行的,因为对于较大的 $n$,它的精度会大大减小,计算的结果可能会失去一些准确性。考虑到这个式子的连续性,我们可以采用计算大量 $n$ 值时能成功的方式——从小到大累加相应的 $i$ 取倒数的值。在具体实现时,需要采用高精度技术,以保证计算过程中的精确性。
在第二种数值问题中,我们需要计算如下的数值:
$$ B=\prod_{i=1}^n {\frac{(i^2+1)}{i^2}} $$
类似于问题一,我们需要考虑到这个式子的连续性。事实上,这个问题可以转化为差分的形式:
$$ B=\prod_{i=1}^n {\frac{(i^2+1)}{i^2}} = \prod_{i=1}^{n-1} {\frac{(i^2+1)}{i^2}}\cdot {\frac{n^2+1}{n^2}} $$
就是说,在相邻因式之间,我们只需要计算它们的比值,也就是:
$$ {\frac{(i^2+1)}{i^2}}\div {\frac{((i-1)^2+1)}{(i-1)^2}}\ =\frac{(i^2+1)\cdot (i-1)^2}{i^2\cdot ((i-1)^2+1)} $$
转化成这个式子后,我们可以采用大整数的技术来求解。
import sys
def solve1(n):
ans = 0
for i in range(1, n+1):
ans += (10**10000 * i + 5) // (10**10000 * i)
return str(ans)[0:n//5] + '.' + str(ans)[n//5:n//5+5]
def solve2(n):
ans = [1]
for i in range(2, n+1):
ans.append(ans[-1] * (10**10000 * i**2 + 1) // (10**10000 * i**2))
res = str(ans[-1])
left = 0
right = len(res)
while left < right - 1:
mid = (left + right) // 2
if res[mid] < '5':
left = mid
else:
right = mid
res = res[0:left] + res[left].replace(res[left], str(int(res[left])-1)) + '0'*(n-len(res[0:left])-1)
return res[0:n//5] + '.' + res[n//5:n//5+5]
n, m = map(int, sys.stdin.readline().strip().split())
if m == 1:
print(solve1(n))
else:
print(solve2(n))
#include <bits/stdc++.h>
using namespace std;
const int N = 10001;
struct Big
{
int a[N], len;
Big()
{
memset(a, 0, sizeof(a)), len = 0;
}
void read()
{
char s[N];
scanf("%s", s+1);
len = strlen(s+1);
for (int i = 1; i <= len; i++) a[i] = s[len-i+1]-'0';
}
void print()
{
printf("%d", a[len]);
for (int i = len-1; i >= 1; i--)
printf("%04d", a[i]);
printf("\n");
}
void operator = (int x)
{
memset(a, 0, sizeof(a));
while (x)
{
a[++len] = x % 10000;
x /= 10000;
}
if (len == 0) len = 1;
}
Big operator + (Big x)
{
Big c = Big(); c.len = max(len, x.len);
for (int i = 1; i <= c.len; i++)
{
c.a[i] += a[i] + x.a[i];
c.a[i+1] += c.a[i]/10000;
c.a[i] %= 10000;
}
if (c.a[c.len+1] > 0) c.len++;
return c;
}
Big operator - (Big x)
{
Big c = Big(); c.len = len;
for (int i = 1; i <= c.len; i++)
{
c.a[i] += a[i] - x.a[i];
if (c.a[i] < 0) c.a[i+1]--, c.a[i] += 10000;
}
while (c.len > 1 && !c.a[c.len]) c.len--;
return c;
}
Big operator * (int x)
{
Big c = Big(); c.len = len;
for (int i = 1; i <= c.len; i++)
{
c.a[i] += a[i] * x;
c.a[i+1] += c.a[i]/10000;
c.a[i] %= 10000;
}
while (c.a[c.len+1]) c.len++;
while (c.len > 1 && !c.a[c.len]) c.len--;
return c;
}
Big operator * (Big x)
{
Big c = Big();
c.len = len + x.len -1;
for (int i = 1; i <= len; i++)
for (int j = 1; j <= x.len; j++)
{
c.a[i+j-1] += a[i] * x.a[j];
c.a[i+j] += c.a[i+j-1]/10000;
c.a[i+j-1] %= 10000;
}
while (c.a[c.len+1]) c.len++;
while (c.len > 1 && !c.a[c.len]) c.len--;
return c;
}
Big operator / (int x)
{
Big c;
int r = 0;
for (int i = len; i >= 1; i--)
{
r = r * 10000 + a[i];
c.a[i] = r / x;
r %= x;
}
c.len = len;
while (c.len > 1 && !c.a[c.len]) c.len--;
return c;
}
};
int n, m;
int main()
{
scanf("%d %d", &n, &m);
if (m == 1)
{
Big ans, sum = Big();
for (int i = 1; i <= n; i++)
sum = sum + Big(i).div(i);
for (int i = 0; i < sum.len; i++)
if (sum.a[i+1] >= 5) {sum.a[i+1] = 0; sum.a[i]++;}
while (sum.len > 1 && !sum.a[sum.len]) sum.len--;
for (int i = sum.len; i > 0; i--)
{
if (i == sum.len) printf("%d.", sum.a[i]);
else printf("%04d", sum.a[i]);
}
printf("\n");
}
else
{
Big ans, sum = Big(1);
for (int i = 1; i <= n-1; i++)
sum = sum * Big(i*i+1).div(i*i);
sum = sum * Big(n*n+1).div(n*n), ans = sum;
for (int i = 0; i < n+4; i++)
if (ans.a[i+1] >= 5) {ans.a[i+1] = 0; ans.a[i]++;}
while (ans.len > 1 && !ans.a[ans.len]) ans.len--;
for (int i = ans.len; i > 0; i--)
{
if (i == ans.len) printf("%d.", ans.a[i]);
else printf("%04d", ans.a[i]);
}
printf("\n");
}
}