第十三届蓝桥杯大赛软件赛决赛Java 研究生组I题

67 阅读2分钟

题解:好等差数列

源题目地址:www.lanqiao.cn/problems/22…

问题描述

给定一个长度为n的数列,进行m次修改操作,每次修改后需要计算当前数列到"好等差数列"的距离。"好等差数列"是指公差为整数的等差数列,距离定义为最少需要修改的元素数量使数列变为好等差数列。

解题思路

  1. 暴力枚举:对于每次修改后的数列,枚举所有可能的公差情况
  2. 频率统计:统计相同元素的数量(公差为0的情况)
  3. 公差计算:对于非零公差,计算所有可能的整数公差及其对应匹配的元素数量
  4. 距离计算:距离 = 数列长度 - 最大匹配元素数量

代码实现

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);

        // 读取输入
        int n = Integer.parseInt(br.readLine());
        int[] a = new int[n];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(st.nextToken());
        }

        int m = Integer.parseInt(br.readLine());
        List<Integer> results = new ArrayList<>();

        // 处理每次修改
        for (int k = 0; k < m; k++) {
            st = new StringTokenizer(br.readLine());
            int p = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            a[p] = v; // 执行修改
            results.add(calculateDistance(a, n));
        }

        // 输出结果
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < results.size(); i++) {
            sb.append(results.get(i));
            if (i < results.size() - 1) sb.append(" ");
        }
        pw.println(sb.toString());
        pw.close();
        br.close();
    }

    // 计算数列到好等差数列的距离
    private static int calculateDistance(int[] a, int n) {
        if (n <= 1) return 0; // 长度≤1的数列本身就是等差数列

        int maxMatches = 0;

        // 情况1:公差为0(所有元素相同)
        Map<Integer, Integer> freqMap = new HashMap<>();
        for (int val : a) {
            freqMap.put(val, freqMap.getOrDefault(val, 0) + 1);
        }
        for (int count : freqMap.values()) {
            maxMatches = Math.max(maxMatches, count);
        }

        // 情况2:公差不为0
        for (int i = 0; i < n; i++) {
            Map<Integer, Integer> diffCounts = new HashMap<>();
            for (int j = i + 1; j < n; j++) {
                long diffVal = (long)a[j] - a[i]; // 使用long防止溢出
                int diffIdx = j - i;
                
                // 检查是否为整数公差
                if (diffVal % diffIdx == 0) {
                    int d = (int)(diffVal / diffIdx);
                    diffCounts.put(d, diffCounts.getOrDefault(d, 0) + 1);
                }
            }
            
            // 更新最大匹配数
            for (int count : diffCounts.values()) {
                maxMatches = Math.max(maxMatches, count + 1); // 包括当前元素i
            }
        }
        return n - maxMatches; // 距离=总长度-最大匹配数
    }
}

关键点说明

  1. 输入处理:使用BufferedReader高效读取输入数据
  2. 修改操作:直接修改数组元素并立即计算距离
  3. 距离计算
    • 统计相同元素数量(公差为0)
    • 枚举所有可能的整数公差
    • 计算每种公差下的匹配元素数量
  4. 结果输出:使用StringBuilder高效构建输出字符串

复杂度分析

  • 时间复杂度:O(m*n²),其中n是数列长度,m是修改次数
  • 空间复杂度:O(n),用于存储数列和中间结果

该解法通过暴力枚举和频率统计,能够正确处理小规模数据(n≤1000),但对于更大规模的数据可能需要更优化的算法。