[COCI 2014/2015 #3] STROJOPIS

GitHub跳转原题关系图返回列表

先把键盘上每个字符预处理成对应手指编号,再顺序扫描整串文本,分别累加 8 根手指的按键次数。

OJ: luogu

题目 ID: P6263

难度:普及-

标签:模拟字符串

日期: 2026-06-19 09:49

题意

给出一串需要输入的字符。

题目已经规定了标准打字法中,每个键应该由哪根手指负责。要求统计除拇指外的 8 根手指,各自需要按多少次键。

思路

这题本质就是一个“字符到手指编号”的映射统计。

最直接的办法,是把每根手指负责的字符列出来,然后逐个字符去查它属于哪一组:

cpp
// brute.cpp:直接按键盘分组逐字符统计每根手指的按键次数。
#include <bits/stdc++.h>
using namespace std;

string s;
int ans[8];

int get_finger(char ch) {
    string group[8] = {
        "1QAZ",
        "2WSX",
        "3EDC",
        "4RFV5TGB",
        "6YHN7UJM",
        "8IK,",
        "9OL.",
        "0P;/-['=]"
    };

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < (int) group[i].size(); j++) {
            if (group[i][j] == ch) {
                return i;
            }
        }
    }
    return -1;
}

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

    getline(cin, s);
    memset(ans, 0, sizeof(ans));

    for (int i = 0; i < (int) s.size(); i++) {
        int id = get_finger(s[i]);
        if (id != -1) {
            ans[id]++;
        }
    }

    for (int i = 0; i < 8; i++) {
        cout << ans[i] << '\n';
    }

    return 0;
}

如何建模

把 8 根手指编号为:

  1. 左手小指
  2. 左手无名指
  3. 左手中指
  4. 左手食指
  5. 右手食指
  6. 右手中指
  7. 右手无名指
  8. 右手小指

然后把题图中属于同一根手指的所有键放进同一个字符串分组里。

例如:

  • 左手小指:1QAZ
  • 左手食指:4RFV5TGB
  • 右手小指:0P;/-['=]

这样每读到一个字符,只要查出它属于哪一组,就能给对应手指计数。

为什么顺序扫描就够了

每个字符对应的负责手指是固定的,不会因为上下文改变。

所以整串文本的答案,就是每个字符独立归类后,把对应手指的计数加一。

代码

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

string s;
int ans[8];
int belong[256];  // 每个字符由哪根手指负责,-1 表示不统计

void init_belong() {
    memset(belong, -1, sizeof(belong));

    string group[8] = {
        "1QAZ",
        "2WSX",
        "3EDC",
        "4RFV5TGB",
        "6YHN7UJM",
        "8IK,",
        "9OL.",
        "0P;/-['=]"
    };

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < (int) group[i].size(); j++) {
            belong[(int) group[i][j]] = i;
        }
    }
}

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

    getline(cin, s);
    init_belong();
    memset(ans, 0, sizeof(ans));

    for (int i = 0; i < (int) s.size(); i++) {
        int id = belong[(int) s[i]];
        if (id != -1) {
            ans[id]++;
        }
    }

    for (int i = 0; i < 8; i++) {
        cout << ans[i] << '\n';
    }

    return 0;
}

复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

其中 n 是字符串长度。预处理字符映射后,每个字符只需要一次常数时间查询。

总结

这题没有算法难点,关键只是把题图里的键位归属抄对。

一旦字符到手指的映射表建好,剩下就是一遍简单统计。