sssanjuu 2024-12-03 23:43 采纳率: 100%
浏览 18
已结题

CF1927D 求Hack

刚入门学算法,有道题(虽然好像只能算思维题)卡了好久找不出bug:CodeForces Round 923 (div3) D:https://codeforces.com/problemset/problem/1927/D

用的cpp,没像题解一样用二分,直接模拟了;cf上WA 了test2;
cf测试点数据太大了看不到wa了哪一个(不是超时应该也不是数组越界),找别人的ac代码用sublime text跑了一千多个test都找不到问题()麻烦帮忙hack இ௰இ Orz

#include <iostream>
#include <vector>
#include <map>
#include <utility>
using namespace std;
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t;
    cin >> t;
    while (t--){
        int n,q,l,r;
        cin >> n;
        vector<int>v(n+5);   // 原数组
        map<int,pair<int,int>>m;   // 自身的下标,<左边第一个不等于自身的值的下标,右边第一个不等于自身的值的下标>
        for (int i = 1; i <= n; i++) cin >> v[i];
        // 预处理
        // 先处理每个数据左边第一个和它不相同的值的下标(先从左到右遍历)
        int lastlastindex = 1,lastlastvalue = v[1];
        int lastindex = 1,lastvalue = v[1];
        for (int i = 2; i <= n; i++){
            if (v[i] != lastvalue){
                m[i].first = lastindex;
                lastlastindex = lastindex;
                lastlastvalue = lastvalue;
                lastindex = i;
                lastvalue = v[i];
            }
            else{
                if (lastvalue != lastlastvalue){
                    m[i].first = lastlastindex;
                }
                else m[i].first = m[lastindex].first;
            }
        }
        // 再处理每个数据右边第一个和它不相同的值的下标(再从右到左遍历)
        lastlastindex = n;
        lastlastvalue = v[n];
        lastindex = n;
        lastvalue = v[n];
        for (int i = n-1; i >= 1; i--){
            if (v[i] != lastvalue){
                m[i].second = lastindex;
                lastlastindex = lastindex;
                lastlastvalue = lastvalue;
                lastindex = i;
                lastvalue = v[i];
            }
            else{
                if (lastvalue != lastlastvalue){
                    m[i].second = lastlastindex;
                }
                else m[i].second = m[lastindex].second;
            }
        }
//        cout << "debug: \n";
//        for (auto x:m) cout << x.first << ",l: " << x.second.first << ",r: " << x.second.second << endl;
        cin >> q;
        while (q--){
            cin >> l >> r;
            if (m[l].second != 0 && m[l].second <= r) cout << l << " " << m[l].second << "\n";
            else if (m[r].first != 0 && m[r].first >= l) cout << m[r].first << " " << r << "\n";
            else cout << -1 << " " << -1 << "\n";
        }
        cout << "\n";
    }
    return 0;
}
  • 写回答

12条回答 默认 最新

  • 问答-莫得感情 2024-12-04 10:19
    关注

    ️题主您好️,目前由我为您解答👇🏼
    🧡参考谷歌智能助手,由吾为汝整理提供🧡

    你的代码的问题在于预处理部分,特别是处理左边/右边第一个不同值时,没有考虑到边界情况以及连续相同数字段的处理。

    以下是一个可以 hack 你的代码的测试用例:

    1
    5
    1 1 1 2 2
    1
    1 5
    

    你的代码会输出 -1 -1,但正确答案应该是 4 5

    问题在于,当处理左边第一个不同值时,你的代码对于第一个连续段的元素,没有正确地设置左边第一个不同值的下标。类似地,在处理右边第一个不同值时,对于最后一个连续段的元素,也没有正确设置。

    以下是修正后的代码:

    #include <iostream>
    #include <vector>
    #include <map>
    #include <utility>
    
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        int t;
        cin >> t;
        while (t--) {
            int n, q, l, r;
            cin >> n;
            vector<int> v(n + 1);
            map<int, pair<int, int>> m;
            for (int i = 1; i <= n; i++) cin >> v[i];
    
            // 预处理左边
            for (int i = 1; i <= n; i++) {
                for (int j = i - 1; j >= 1; j--) {
                    if (v[j] != v[i]) {
                        m[i].first = j;
                        break;
                    }
                }
            }
    
            // 预处理右边
            for (int i = 1; i <= n; i++) {
                for (int j = i + 1; j <= n; j++) {
                    if (v[j] != v[i]) {
                        m[i].second = j;
                        break;
                    }
                }
            }
    
            cin >> q;
            while (q--) {
                cin >> l >> r;
                if (m[l].second != 0 && m[l].second <= r) cout << l << " " << m[l].second << "\n";
                else if (m[r].first != 0 && m[r].first >= l) cout << m[r].first << " " << r << "\n";
                else cout << -1 << " " << -1 << "\n";
            }
            cout << "\n";
        }
        return 0;
    }
    

    改进建议:

    虽然上面的代码解决了你的bug,但效率不高,预处理部分的时间复杂度是 O(n^2),在 n 较大时可能会超时。建议你参考题解使用二分或者其他更优的算法来预处理左右边界,将时间复杂度降到 O(n log n) 或 O(n)。 例如,可以使用 std::vector<std::vector<int>> 来存储每个数字出现的位置,然后用二分查找来快速确定左右边界。

    这个修改后的代码更简洁,也更容易理解和调试。 记住,处理边界情况非常重要,尤其是在处理数组或其他数据结构时。 希望这个解释和修改后的代码能够帮到你!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(11条)

报告相同问题?

问题事件

  • 系统已结题 12月12日
  • 已采纳回答 12月4日
  • 赞助了问题酬金15元 12月4日
  • 创建了问题 12月3日