String Game

題目

有兩個字串 ttpp (1pt200000)(1 \leq |p| \leq |t| \leq 200000),還有一個序列 a1...ata_1 ... a_{|t|} (1ait)(1 \leq a_i \leq |t|)。每一次會依照序列刪除 tt 裡面的數字,請求出最多可以刪除幾次使得新的 tt 仍舊包含 pp。(在每一次刪除資源後,編號不會改變)

(這裡的「包含」和平常的包含不一樣,這邊是指如果字串 ss 能在刪除一些字元後得到字串 tt,則 ss 包含 tt。)

解題思路

一個一個刪除再檢查的時間複雜度為 O(t2)O(t^2),太慢了。這時候一樣可以對答案二分搜。

如果刪除完 kk 次後,tt 還包含 pp,則刪除 kk 次以內 tt 也一定包含 pp。刪除 kk 次後,tt 不包含 pp,則刪除 kk 次以上的 tt 也一定不會包含 pp

用對答案二分搜的技巧,時間複雜度優化成 O(tlog(t))O(tlog(t))

常見錯誤

  • 在刪除字元以後編號不會改變
  • 要注意字串的 indexindex 還有 aia_i 是從 11 還是從 00 開始

完整程式碼

#include <bits/stdc++.h>
 
using namespace std;
 
int main() {
    string t, p;
    cin >> t >> p;
    vector<int> order(t.size());
    for (int i = 0; i < t.size(); i++) {
        cin >> order[i];
    }
    int l = 0, r = t.size();
    while (l < r) {
        int m = (l + r + 1) / 2;
        vector<int> deleted(t.size());
        for (int i = 0; i < m; i++) {
            deleted[order[i] - 1] = 1;
        }
        int cur = 0;
        for (int i = 0; i < t.size() && cur < p.size(); i++) {
            if (!deleted[i] && p[cur] == t[i]) {
                cur++;
            }
        }
        if (cur == p.size()) {
            l = m;
        }
        else{
            r = m - 1;
        }
    }
    cout << l << "\n";
}