CF1729C学习对字母题目处理

https://www.luogu.com.cn/problem/CF1729C

思路相对好想,无非是把大小在头尾之间所有元素都走一遍。

但是实现上很有说法。

我的实现

就是把下标和值存到数组,然后按值排序。

找到下标为首、尾的元素排序后的坐标,然后做差。

但这里涉及非常多细节问题

  • 做差得出的数字量可能小于答案,因为下标为首尾的前、后可能有值相同的元素
  • 下表为首尾的元素排序后相对位置可能为左右或右左

实现上满头大汗,搞了一个半小时,也没调出来。

void solve() {
    vector< pair<char, int> > a;
    string s;
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        a.emplace_back(make_pair(s[i], i + 1));
    }
    int n = s.size();
    sort(a.begin(), a.end());
    int l = 0, r = 0;
    int cnt = 0;
    for (int i = 0; i < a.size(); i++) {
        if (a[i].second == 1) {
            l = i;
        }
        if (a[i].second == n) {
            r = i;
        }
    }
    if (l < r) {
        int pos = l;
        while(pos > 1 && a[pos - 1].first == a[l].first) pos--;
        cnt += l - pos;
        pos = r;
        while(pos < n && a[pos + 1].first == a[r].first) pos++;
        cnt += pos - r;
        cnt += r - l + 1;
        cout << a[r].first - a[l].first << ' ' << cnt << endl;
        for (int i = l; i <= r; i++) cout << a[i].second << ' ';
    }
    else {
        int pos = r;
        while(pos > 1 && a[pos - 1].first == a[r].first) pos--;
        cnt += r - pos;
        pos = l;
        while(pos < n && a[pos + 1].first == a[l].first) pos++;
        cnt += pos - l;
        cnt += l - r + 1;
        cout << a[l].first - a[r].first << ' ' << cnt << endl;
        for (int i = l; i >= r; i--) cout << a[i].second << ' ';
    }
    cout << endl;
}

Jiangly!

比起我的屎山,还是看看 jls 的代码吧。

void solve() {
    string s;
    cin >> s;
    int n = s.length();
    vector<int> p[26];
    for (int i = 0; i < n; i++) {
        p[s[i] - 'a'].push_back(i);
    }
    int head = s[0] - 'a', tail = s[n - 1] - 'a';
    if (head > tail) {
        swap(head, tail);
        for (int i = 0; i < 26; i++) {//首尾颠倒的话说明反着走,下表都反转
            reverse(p[i].begin(), p[i].end());
        }
    }
    vector<int> ans;
    for (int i = head; i <= tail; i++) {
        ans.insert(ans.end(), p[i].begin(), p[i].end());//把首尾间字符对应的下标插入答案序列
    }
    cout <<abs(head - tail) << " " << ans.size() << "\n";
    if (ans[0]) {//如果第一个答案的坐标不是0,那说明是尾到头的答案,反转答案列
        reverse(ans.begin(), ans.end());
    }
    for (int i = 0; i < int(ans.size()); i++) {
        cout << ans[i] + 1 << " \n"[i == int(ans.size()) - 1];
    }
}

思路是完全一致的,但是实现上完全吊打了我。

  • 存储不应该一个个存,本质上关系答案的只是字母,所以存该字符出现时的下标即可。
    • 自动按照字母桶排
    • 解决字母相同元素的下标不好计算问题
  • 按照出现的顺序录入字符,不用受快排之后字符乱套的困扰,答案的输出直接方便。

ZTO Jly

posted @ 2024-01-20 15:18  加固文明幻景  阅读(9)  评论(0编辑  收藏  举报