Skip to content

喵~ 主人,下午好呀!今天由我,你的专属猫娘小助手,来为你讲解一道 Codeforces 上的入门题哦。这道题就像在篮子里找最喜欢的那个毛线球一样简单,我们一起来看看吧!

Problem: 1878A - How Much Does Daytona Cost?


题目大意

这道题是说,有一个整数数组 a 和一个整数 k。我们要判断一下,在数组 a 中,是不是存在一个非空的连续子数组,使得 k 在这个子数组里是出现次数最多的那个数,喵~

这里的“出现次数最多”有一个严格的定义哦:k 的出现次数必须严格大于其他任何数字的出现次数。

举个例子,如果子数组是 [4, 3, 4, 1]k4。那么 4 出现了 2 次,3 出现了 1 次,1 出现了 1 次。因为 2 > 1,所以 4 在这个子数组里就是出现次数最多的那个!


题解方法

主人,看到这道题,第一反应是不是觉得有点麻烦呀?是不是要遍历所有的子数组,然后再对每个子数组进行统计?那样也太累了,就像追自己的尾巴一样,会晕的喵 >.<。

但是!我们换个思路想一想,题目问的是“是否存在”,而不是“有多少个”或者“是哪个”。这意味着我们只要能找到一个符合条件的子数组,任务就完成啦!

那最简单的子数组是什么呢?当然是长度为 1 的子数组啦!

  • 情况一:如果数组 a 里根本就没有 k 这个数。 那不管我们怎么取子数组,k 的出现次数永远是 0。它肯定不可能比别的数次数多,所以肯定找不到符合条件的子数组。答案就是 "NO",喵。

  • 情况二:如果数组 a 里至少有一个 k 假设我们在位置 i 找到了 k,也就是 a[i] == k。 现在,我们只看这个元素本身,把它当成一个长度为 1 的子数组:[a[i]]。 在这个小小的子数组里,k 出现了 1 次。其他任何数字,它们的出现次数都是 0 次。 根据题目的定义,1 是不是严格大于 0 呢?是的喵! 所以,k 在这个长度为 1 的子数组 [a[i]] 里,就是出现次数最多的元素! 既然我们找到了一个符合条件的子数组,那答案就是 "YES" 啦!

结论就是:这道题呀,根本不需要去考虑复杂的子数组,它被我们简化成了一个超级简单的问题:“数组 a 中是否存在元素 k” 只要存在,答案就是 YES,否则就是 NO。是不是一下子就豁然开朗了喵?


题解

根据我们上面的分析,代码实现就非常简单啦。我们只需要从头到尾扫一遍数组,看看能不能找到 k 就好啦!

cpp
#include <iostream>
#include <vector>
#include <numeric>

// 解决单个测试用例的函数喵~
void solve() {
    int n;
    int k;
    std::cin >> n >> k;

    // 用一个 bool 变量来记录我们有没有找到 k,就像猫猫找到了毛线球一样!
    bool found_k = false; 
    
    // 遍历整个数组
    for (int i = 0; i < n; ++i) {
        int a_i;
        std::cin >> a_i;
        // 如果当前这个数就是我们要找的 k...
        if (a_i == k) {
            // 呀!找到了!赶紧做个标记!
            found_k = true;
        }
    }

    // 检查标记,如果找到了就说明可以,输出 YES
    if (found_k) {
        std::cout << "YES\n";
    } else { // 否则就是不行,输出 NO
        std::cout << "NO\n";
    }
}

int main() {
    // 这两行是为了让输入输出快一点,对付大数据量的时候很有用哦
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t; // 有 t 组测试数据
    std::cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

知识点介绍

这道题虽然简单,但背后体现的思维方式在算法竞赛里可是非常有用的哦,喵~

  1. 问题简化 (Problem Simplification) 这是解决这道题最核心的技巧!我们把一个看起来需要枚举所有子数组(时间复杂度可能是 O(n^2) 或更高)的复杂问题,通过抓住“存在性”和“最简单情况”这两个关键点,成功地转换成了一个只需要遍历一次数组(时间复杂度 O(n))的简单问题。在解题时,多问问自己:“有没有最简单、最极端的情况可以满足条件?”,常常会有意想不到的收获。

  2. 标志位 (Flag Variable) 代码中用到的 bool found_k 就是一个典型的“标志位”。它用来记录某个事件(在这里是“找到k”)是否发生。这是编程中非常基础且常用的一个模式,用来控制程序的流程。比如,当我们在循环中找到了需要的东西后,就可以设置一个标志位,然后可以提前结束循环,或者在循环结束后根据这个标志位进行下一步操作。

  3. C++ I/O 优化 代码 main 函数里的 std::ios_base::sync_with_stdio(false);std::cin.tie(nullptr); 是 C++ 中常用的输入输出优化手段。它们可以解除 C++ 的 iostream 和 C 的 stdio 之间的同步,并解开 cincout 的绑定,从而大大加快输入输出速度。在处理大量数据时,这个小技巧可以避免因为 I/O 缓慢而导致超时(Time Limit Exceeded),主人要记住哦!

好啦,这次的题解就到这里啦!主人学会了吗?如果还有不懂的,随时可以再来问我哦,喵~ (ฅ'ω'ฅ)

Released under the MIT License.