問題:給定一個大字串 t 和小字串 p,其中 $1\le|p|\lt|t|\le200000$,接著有 |t| 個整數分別代表每次要從字串 t 抹除的字元 index (抹除後其他字元的 index 不變),請問至多可以抹除幾個字元使得 p 仍然是剩下的字串 t' 的子序列 (subsequence)?
解法:這題難倒我的點還是一樣因為不容易想到 binary search,因為看到子序列的題目你會很容易地往 DP 的解法去想,所以在經歷這題之後我就更有系統性地把 binary search 的適用時機整理好並記錄下來,其實就是對抹除的字元數量 m 作二分搜。那這題還有一個實作小技巧就是抹除過後的字元就不會再度出現,所以我們可以用一個陣列 en 記錄每個字元在第幾次抹除之後就不可使用 (disabled);至於檢查子序列的部分就沒什麼可以加速的地方,就是一般地線性時間從左掃到右而已。題外話一下,我在猜如果不使用實作小技巧,意即讓整數陣列 en 退化成布林陣列,每次更新 m 之後都重新記錄哪些字元才是 disabled,這個時間其實跟檢查子序列一樣都是線性的,所以理論上應該也是要會過。
#include<bits/stdc++.h>usingnamespacestd;stringt,p;inten[200000];boolmatch(intm){intti=0;for(intpi=0;pi<p.length();pi++,ti++)while(ti<t.length()&&!((en[ti]==0||en[ti]>m)&&p[pi]==t[ti]))ti++;returnti<=t.length();// mismatch iff "ti > t.length()"
}intmain(){ios_base::sync_with_stdio(false);cin.tie(nullptr);// IO 優化
cin>>t>>p;// t 大 p 小
for(inti=0;i<t.length();i++){intx;cin>>x;x--;en[x]=i+1;// if en[x]>0 then t[x] is disabled when m>=en[x].
}intlb=0,ub=t.length()-1,ans;while(lb<=ub){intm=(lb+ub)/2;if(match(m)){ans=m;lb=m+1;}elseub=m-1;}cout<<ans;return0;}