[SHUPC 2024] 函数 的题解


记住只在没有思路时使用题解,不要从它复制粘贴代码。请尊重题目和题解的作者。
在解题之前提交题解的代码会导致封禁。

作者: admin

概述

本题要求计算函数 f(x) = x - 0.5 + \arctan(\cot(\pi x)) / \pi 在 T 个询问点 x 上的取值,允许 10^{-6} 的误差。核心解法是利用三角恒等式把 f(x) 化简为下取整函数 \lfloor x \rfloor,从而避免对原式做高精度浮点计算。

分析
核心观察

由 \cot \theta = \tan(\pi/2 - \theta) 以及 \arctan 返回主值区间的性质,可以把 \arctan(\cot(\pi x)) 精确表示成只与 x 小数部分有关的量;代入原式后恰好消去 x 与 -0.5,最终结果就是 \lfloor x \rfloor。

思路

设 x = m + s,其中 m = \lfloor x \rfloor,s = \{x\} 为小数部分。由于 x \notin \N,有 s \in (0, 1)。

因为 \cot 以 \pi 为周期:

\displaystyle  \cot(\pi x) = \cot(\pi(m + s)) = \cot(\pi s)

又 \cot(\pi s) = \tan(\pi/2 - \pi s) = \tan(\pi(1/2 - s)),且 0 < s < 1 保证 \pi(1/2 - s) \in (-\pi/2, \pi/2),恰好落在 \arctan 的主值区间内,于是:

\displaystyle  \arctan(\cot(\pi x)) = \pi\left(\frac{1}{2} - s\right)

代入原式:

\displaystyle  f(x) = m + s - \frac{1}{2} + \frac{1}{2} - s = m = \lfloor x \rfloor

因此每个询问的答案就是 \lfloor x \rfloor。若直接按原式用浮点计算 \cot(\pi x),当 x 接近 10^9 时 \pi x 的浮点表示误差会使结果完全失真,所以必须使用化简后的形式。

具体示例

以 x = 1.72 为例:m = 1,s = 0.72,则 \arctan(\cot(\pi x)) = \pi(0.5 - 0.72) = -0.22\pi,于是 f(1.72) = 1.72 - 0.5 - 0.22 = 1.00。同理,直接验证 \lfloor 1.10 \rfloor = 1、\lfloor 1.72 \rfloor = 1、\lfloor 2.34 \rfloor = 2,与样例输出一致。

算法步骤
  1. 读入询问组数 T。
  2. 对每个询问,读入浮点数 x,计算 ans 为 \lfloor x \rfloor(可用 floor 函数实现)。
  3. 输出 ans,保留 6 位小数。
复杂度分析

时间:O(T)

空间:O(1)

实现注意事项
  • 输入保证 x \notin \N,即 \sin(\pi x) \ne 0,f(x) 总有定义,且小数部分 s \in (0, 1) 使主值恒等式严格成立。
  • 切勿直接按原式计算:x 最大可达 10^9,double 无法精确表示 \pi x,取 \cot 时会严重失真。
  • 因 x \ge 0 且不是整数,\lfloor x \rfloor 即为其整数部分,用 floor 函数或向零取整均可。
  • 输出保留 6 位小数与样例格式一致;本题按误差判定,直接输出整数同样正确。
  • T \le 10^4,输入数据较多,建议开启快速输入输出。
源代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    cout << fixed << setprecision(6);
    while (T--) {
        double x;
        cin >> x;
        cout << floor(x) << '\n';
    }
    return 0;
}
import sys
from math import floor

def main():
    data = sys.stdin.buffer.read().split()
    t = int(data[0])
    out = []
    for i in range(1, t + 1):
        x = float(data[i])
        out.append(f"{floor(x):.6f}")
    sys.stdout.write("\n".join(out))

if __name__ == "__main__":
    main()

评论

目前没有评论。