AtCoder Beginner Contest 372 補題記錄

klr_i發表於2024-09-23

A - delete

題意:

輸出刪除字串中 . 後的字串

思路:

只輸出字串中不是 . 的字元

void solve()
{
    string s = sread();
    for(auto it:s) if(it!='.') cout<<it;
    cout<<endl;
}

B - 3^A

題意:

給出 M , 求將M拆分成 N 個 3的 \(A_i\) 次方 相加

思路:

貪心,從大到小用 \(A_i\) 減M,最後一定能在 N<=20 範圍內將M減為0

void solve()
{
    int m = read();
    int a = 10;
    vector<int> ans;
    while(m>0){
        if(m >= pow(3,a)){
            ans.push_back(a);
            m -= pow(3,a);
        }else {
            a--;
        }
    }

    cout<<ans.size()<<endl;
    for(auto it:ans) write(it); ED;
}

C - Count ABC Again

題意:

給定字串 \(S\)\(Q\) 次詢問,每次詢問將字串 \(S\) 的第 \(X\) 個字元更改為 \(C\),並輸出每次更改後字串中包含子串 \(ABC\) 的個數

思路:

- 每次詢問都去統計子串的個數肯定會超時
- 只在初始統計一次子串的個數

  • 考慮到每次修改都只會影響周圍的幾個字元,所以每次修改只會讓子串的個數加一或減一或不加不減
    - 當修改破壞了原本的子串時,\(cnt\) 減一
    - 當修改形成了新的子串時, \(cnt\) 加一
void solve()
{
    int n = read(), q = read();
    string s = sread();

    int cnt = 0;
    for(int i=0;i<n-2;i++){
        if(s[i] == 'A' && s[i+1] == 'B' && s[i+2] == 'C'){
            cnt++;
        }
    }

    auto del = [&](int x){
        if((s[x] == 'A' && x < n-2 && s[x+1] == 'B' && s[x+2] == 'C')
        || (s[x] == 'B' && (x>0 && x<n-1) && s[x-1] == 'A' && s[x+1] == 'C')
        || (s[x] == 'C' && x > 1 && s[x-1] =='B' && s[x-2] == 'A'))
            cnt --;
    };

    auto add = [&](int x,char c){
        if((c == 'A' && x < n-2 && s[x+1] == 'B' && s[x+2] == 'C')
        || (c == 'B' && (x>0 && x<n-1) && s[x-1] == 'A' && s[x+1] == 'C')
        || (c == 'C' && x > 1 && s[x-1] =='B' && s[x-2] == 'A')){
            cnt ++;
        }
        s[x] = c;
    };

    while(q--){
        int x = read() - 1;
        char c; cin>>c;
        if(s[x] == c){
            cout<<cnt<<endl;
            continue;
        }
        del(x);
        add(x, c);
        cout<<cnt<<endl;
        //cout<<s<<endl;
    }
}

D - Buildings

題意:

給定 \(N\) 個建築,依次求當 \(i = 1,2,...N\) 的時候 符合以下條件的 \(j\) 的個數
\(i\)\(j\) 之間沒有比\(j\)更高的建築物

思路:

- 考慮到 \(i\) 從1到N在不斷刪減元素比較複雜,就從後往前處理,每次增加一個元素
- 維護一個遞增的序列,每次新增元素就把新元素前面的元素(比該元素小的元素)都刪除,因為新的元素比這些元素考前而比他們大,必定不能符合條件(類似於優先佇列的思想)該序列的大小就是每次符合條件的個數

  • 具體用 \(set\) 容器來實現,每次新增元素就 lower_bound 找到該元素在遞增序列的位置,並用迭代器將查到的位置前面的元素全部刪除,時間複雜度 \(O(nlongn)\)
void solve()
{
    int n = read();
    vector<int> v;
    for(int i=0;i<n;++i) v.emplace_back(read());
    
    set<int> st;
    vector<int> ans(n);
    ans[n-1] = 0;
    for(int i=n-1;i>0;i--){
        auto it = st.lower_bound(v[i]);
        if(it != st.end() && it != st.begin()){
            it--;
            while(it != st.begin()){
                it--;
                st.erase(next(it));
            }
            st.erase(it);
        }else if(it == st.end()){
            st.clear();
        }
        st.insert(v[i]);
        ans[i-1] = st.size()
    }
    for(auto it:ans) write(it); ED;
}

相關文章