my-love-for-tomorrow

导航

C. Traffic Light 10.23

https://codeforces.com/problemset/problem/1744/C

就普通题,先看看小蒟蒻自己的代码吧

    #include<iostream>
    #include<string>
    #include<vector>
    #include<algorithm>
    using namespace std;
    //自己的代码test5超时
    bool judge(int mid ,string &s,vector<int> position){
        int Maxtime=0,midTime=0;
        for(int i=0;i<position.size();i++){
            int nt=position[i]+1;
            if(nt>=s.size()) nt=0;
            for(int j=nt;j<s.size();j++){
                midTime++;
                if(s[j]!='g'){
                    if(j==s.size()-1) j=-1;
                    continue;
                }else{
                    Maxtime=max(Maxtime,midTime);
                    midTime=0;
                    if(Maxtime>=mid) return true;
                    break;
                }
            }
        }
        return Maxtime>=mid;
    }
    int main(){
        std::ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin>>t;
        while(t--){
          int n;
          char c;
          string line;
          vector<int> position;
          cin>>n;
          cin>>c;
          cin>>line;
          if(c=='g'){
            cout<<"0\n";
          }
          else{
                for(int i=0;i<line.size();i++){
                    if(line[i]==c){
                        position.push_back(i);
                    }   
                }
                int mid;
                int l=0,r=line.size();
                while (l+1<r)
                {
                    mid=(l+r)>>1;
                    if(judge(mid,line,position)){
                        l=mid;
                    }else{
                        r=mid;
                    }
                }
            cout<<l<<"\n";
           }
          
        }
        return 0;
    }
  

因为在judge函数中,查找距离时,时间复杂度到了O(n^2),很难接受了,导致test5数据超时。

我找ai询问,告诉我预处理‘g'的位置,不用预处理c的位置,我感觉两个位置都与处理一下,直接计算距离会更好,然后我就准备改代码了(这次代码就已经过了)

    #include<iostream>
    #include<string>
    #include<vector>
    #include<algorithm>
    using namespace std;
    bool judge(int mid ,string &s,vector<int>& position,vector<int>& g_pos){
        int dist=-1;
        for(auto i:position){
            auto it=lower_bound(g_pos.begin(),g_pos.end(),i);
            if(it!=g_pos.end()){
                dist=*it-i;
            }else{
                dist=s.size()-i+g_pos[0];
            }
            if(dist>=mid) return true;
        }

        return dist>=mid;
    }
    int main(){
        std::ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin>>t;
        while(t--){
          int n;
          char c;
          string line;
          vector<int> position;
          vector<int> g_pos;
          cin>>n;
          cin>>c;
          cin>>line;
          if(c=='g'){
            cout<<"0\n";
          }
          else{
                for(int i=0;i<line.size();i++){
                    if(line[i]==c){
                        position.push_back(i);
                    }else if(line[i]=='g'){
                        g_pos.push_back(i);
                    }   
                }
                int mid;
                int l=0,r=line.size();
                while (l+1<r)
                {
                    mid=(l+r)>>1;
                    if(judge(mid,line,position,g_pos)){
                        l=mid;
                    }else{
                        r=mid;
                    }
                }
            cout<<l<<"\n";
           }
          
        }
        return 0;
    }

最后,ai告诉我了一种线性的办法

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    
    while (t--) {
        int n;
        char c;
        string line;
        cin >> n;
        cin >> c;
        cin >> line;
        
        if (c == 'g') {
            cout << "0\n";
            continue;
        }
        
        // 将字符串复制一份来模拟环形
        line = line + line;
        
        int maxWait = 0;
        int lastG = -1;
        
        // 从后往前遍历
        for (int i = line.length() - 1; i >= 0; i--) {
            if (line[i] == 'g') {
                lastG = i;
            }
            if (lastG != -1 && i < n && line[i] == c) {
                maxWait = max(maxWait, lastG - i);
            }
        }
        
        cout << maxWait << "\n";
    }
    
    return 0;
}

还有一种最高效的二分,ai说的

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    
    while (t--) {
        int n;
        char c;
        string s;
        cin >> n >> c >> s;
        
        if (c == 'g') {
            cout << "0\n";
            continue;
        }
        
        // 将字符串复制一份处理环形
        s = s + s;
        vector<int> g_pos;
        for (int i = 0; i < 2 * n; i++) {
            if (s[i] == 'g') {
                g_pos.push_back(i);
            }
        }
        
        // 二分答案
        int left = 1, right = n, ans = 0;
        
        while (left <= right) {
            int mid = (left + right) / 2;
            bool valid = false;
            
            for (int i = 0; i < n; i++) {
                if (s[i] == c) {
                    // 在g_pos中查找第一个 >= i + mid 的g
                    auto it = lower_bound(g_pos.begin(), g_pos.end(), i + mid);
                    if (it != g_pos.end() && *it - i <= n) {
                        valid = true;
                        break;
                    }
                }
            }
            
            if (valid) {
                ans = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        cout << ans << "\n";
    }
    
    return 0;
}

对于可能循环的问题,很好的办法就是写两遍,就是s=s+s

posted on 2025-10-23 10:25  lQvQe  阅读(5)  评论(0)    收藏  举报