1 条题解

  • 0
    @ 2024-12-25 23:32:21

    解决思路

    1. 好数序列分析
      • 如果公差 D<0D < 0,序列递减,需将 AA 转化为第 NN 项的值,将 DD 取绝对值以便统一处理递增序列。
      • 转化后,序列形式为 A,A+D,A+2D,,A+(N1)DA, A+D, A+2D, \ldots, A+(N-1)D
    2. 二分查找
      • 将好数序列视为一个递增数组,使用二分查找定位 XX 在序列中的最近位置。
      • 二分查找的目标是找到一个索引 kk,使得 A+kDA + k \cdot D 最接近 XX
    3. 检查附近的项
      • 由于二分查找找到的位置可能不是最优解,还需检查二分附近的几项(例如 k1,k,k+1k-1, k, k+1),找出与 XX 的最小绝对差。
    4. 时间复杂度
      • 构造序列的一般项计算复杂度为 O(1)O(1)
      • 二分查找的时间复杂度为 O(logN)O(\log N)
      • 最多检查 10 项附近值,时间复杂度为常数级。
      • 总复杂度为 O(logN)O(\log N)

    代码详解

    1. 输入数据预处理
      • 如果 D<0D < 0,将序列起始值 AA 转化为最后一项 A+(N1)DA + (N-1)D,并将 DD 取绝对值。
      • 这样,序列转化为递增序列。
    2. 二分查找
      • 定义查找范围为 [0,N1][0, N-1],取中间值计算该项对应的数值。
      • 比较中间项和 XX 的大小,调整查找范围,直到找到最近的位置。
    3. 周边值检查
      • 检查二分查找附近的几项(例如 k5k-5k+5k+5,确保不越界),计算与 XX 的绝对差。
    4. 输出结果
      • 输出最小绝对差。
    #include<bits/stdc++.h>
    
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(0);
        cin.tie(0);
    
        long long x, a, d, n;
        cin >> x >> a >> d >> n;
    
        // 处理递减序列,将其转为递增序列
        if (d < 0) {
            a = a + d * (n - 1);
            d = -d;
        }
    
        // 二分查找最近的项
        long long l = 0, r = n - 1;
        while (l <= r) {
            long long m = (l + r) / 2;
            if (a + d * m < x) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
    
        // 检查附近的项
        long long res = LLONG_MAX;
        for (long long i = max(0LL, l - 5); i <= min(n - 1, l + 5); i++) {
            res = min(res, abs(a + d * i - x));
        }
    
        // 输出结果
        cout << res << '\n';
        return 0;
    }
    
    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            long x = sc.nextLong();
            long a = sc.nextLong();
            long d = sc.nextLong();
            long n = sc.nextLong();
    
            // 转换递减为递增序列
            if (d < 0) {
                a = a + d * (n - 1);
                d = -d;
            }
    
            // 二分查找最近的位置
            long l = 0, r = n - 1;
            while (l <= r) {
                long m = (l + r) / 2;
                if (a + d * m < x) {
                    l = m + 1;
                } else {
                    r = m - 1;
                }
            }
    
            // 检查附近的值
            long res = Long.MAX_VALUE;
            for (long i = Math.max(0, l - 5); i <= Math.min(n - 1, l + 5); i++) {
                res = Math.min(res, Math.abs(a + d * i - x));
            }
    
            // 输出结果
            System.out.println(res);
        }
    }
    
    def closest_good_number(x, a, d, n):
        # 转换递减为递增序列
        if d < 0:
            a = a + d * (n - 1)
            d = -d
    
        # 二分查找最近的位置
        l, r = 0, n - 1
        while l <= r:
            m = (l + r) // 2
            if a + d * m < x:
                l = m + 1
            else:
                r = m - 1
    
        # 检查附近的值
        res = float('inf')
        for i in range(max(0, l - 5), min(n - 1, l + 5) + 1):
            res = min(res, abs(a + d * i - x))
    
        # 输出结果
        return res
    
    
    # 输入
    x, a, d, n = map(int, input().split())
    print(closest_good_number(x, a, d, n))
    

    信息

    ID
    234
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    60
    已通过
    5
    上传者