题解:洛谷 P3741 小果的键盘

【题目来源】

洛谷:P3741 小果的键盘 - 洛谷

【题目描述】

一天,她打出了一个只有这两个字符的字符串。当这个字符串里含有 VK 这个字符串的时候,honoka 就特别喜欢这个字符串。所以,她想改变至多一个字符(或者不做任何改变)来最大化这个字符串内 VK 出现的次数。给出原来的字符串,请计算她最多能使这个字符串内出现多少次 VK(只有当 VK 正好相邻时,我们认为出现了 VK。)

【输入】

第一行给出一个数字 \(n\),代表字符串的长度。

第二行给出一个字符串 \(s\)

【输出】

第一行输出一个整数代表所求答案。

【输入样例】

20
VKKKKKKKKKVVVVVVVVVK

【输出样例】

3

【核心思想】

  1. 问题分析:给定一个只包含 VK 的字符串,最多可以修改一个字符(VKKV)或不修改,目标是使字符串中相邻的 VK 子串出现次数最多。本质是一个字符串贪心匹配问题,需要先统计原有 VK 对,再判断是否可以通过一次修改创造一个新的 VK 对。

  2. 算法选择

    • 贪心两遍扫描
      • 第一遍:从左到右统计所有现存的 VK 对,并将它们标记为已使用(避免重叠干扰后续修改判断)。这一步尽可能多地保留原有配对。
      • 第二遍:在剩余未标记的字符中,检查是否存在 VVKK 的相邻组合。因为修改其中一个字符可以形成一个新的 VK,且不会与已有的 VK 重叠。
    • 正确性:由于一个字符只能属于一个 VK 对,第一遍贪心统计所有不重叠的 VK 对是最优的。之后若存在可修改的位置,最多增加一个额外的 VK
  3. 关键步骤

    • 读入:读取 n 和字符串 s
    • 第一遍统计:遍历 i0n-2,若 s[i]=='V' && s[i+1]=='K',则 ans++,并将这两个字符标记为 'A'(或任意非 V/K 字符),防止它们被第二遍重复使用。
    • 第二遍检查:再次遍历 i0n-2,若 s[i]=='V' && s[i+1]=='V's[i]=='K' && s[i+1]=='K',则 ans++ 并跳出(因为最多修改一次)。
    • 输出ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),只需两次线性扫描。
    • 空间复杂度:\(O(1)\),在原字符串上修改,额外空间常数。
  5. 贪心与字符串修改

    • 避免重叠:标记已使用的 VK 对非常重要,否则第二遍可能会基于已经配对的字符进行修改,导致计数错误(例如 VVK 中,第一遍统计了 VK,第二遍若看到 VV 可能会错误地增加计数)。
    • 最多一次修改:第二遍只要找到一个可行的 VVKK,就足以通过一次修改增加一个 VK,因此找到后立即跳出循环。
    • 特殊情形:如果字符串本身没有 VK,但存在 VVKK,则可以通过一次修改得到 1 个 VK
    • 适用场景:这类“最多修改一次最大化特定子串数量”的贪心问题,常见于字符串处理竞赛题。

【算法标签】

入门 #字符串入门

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, ans = 0;  // n: 字符串长度,ans: 计数器
    string s;  // 输入的字符串

    cin >> n >> s;  // 读入字符串长度和字符串

    // 第一遍遍历:查找"VK"组合
    for (int i = 0; i < n - 1; i++)
    {
        if (s[i] == 'V' && s[i + 1] == 'K')  // 找到"VK"组合
        {
            ans++;  // 计数器加1
            s[i] = 'A';  // 将'V'标记为已使用
            s[i + 1] = 'A';  // 将'K'标记为已使用
        }
    }

    // 第二遍遍历:查找可以修改一次的额外组合
    for (int i = 0; i < n - 1; i++)
    {
        if (s[i] == 'V' && s[i + 1] == 'V')  // 找到"VV"组合
        {
            ans++;  // 可以修改一个字符得到"VK"
            break;  // 只需要一次修改
        }
        if (s[i] == 'K' && s[i + 1] == 'K')  // 找到"KK"组合
        {
            ans++;  // 可以修改一个字符得到"VK"
            break;  // 只需要一次修改
        }
    }

    cout << ans;  // 输出最大"VK"数量
    return 0;
}

【运行结果】

20
VKKKKKKKKKVVVVVVVVVK
3
posted @ 2026-08-30 09:18  团爸讲算法  阅读(20)  评论(0)    收藏  举报