D1 题目链接
题目大意是有一个原串s 和 模式串 t ,保证 t 是 s 的子序列 ,二者长度均小于200,现在可以将原串s中删去一个子串再将剩余部分拼起来,使得修改后的s仍有一个子序列与t相等,现在问满足条件的删去子串的最长长度。
直接暴力尝试删去每个子串,再检查剩余部分是否有子序列与t相等。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 200 + 10; 5 6 bool checksub(string s,string t,int lent){ 7 int lens = s.length(); 8 int ind = 0; 9 for (int i = 0; i < lens; ++i) { 10 if(s[i] == t[ind]) ind++; 11 if(ind == lent){ 12 return true; 13 } 14 } 15 return false; 16 } 17 18 int main(){ 19 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 20 string strS,strT; 21 cin >> strS >> strT; 22 int lenS = strS.length() , lenT = strT.length(); 23 int ans = 0; 24 for (int i = 0; i < lenS; ++i) { 25 for (int j = i; j < lenS; ++j) { 26 string tmp = strS; 27 tmp.erase(i,j-i+1); 28 if(checksub(tmp,strT,lenT)){ 29 ans = max(ans, j- i + 1); 30 } 31 } 32 } 33 cout << ans ; 34 return 0; 35 }
复杂度差不多是O(n^3)。
D2 题目链接
题目与D1相同,只是长度限制由200变为2e5,不能暴力了。
暴力做法里有很多删去子串是不满足剩余部分仍含有子序列t的,其实就是有很多不必要的删去。试想一个满足条件的删去,删后的左边子串一定是包含t的左侧某部分,删后的右边子串则是包含t的右侧某部分,然后我们尽量拉长这个删去子串直到遇到t的匹配字符位置。这样理解问题就变成找出t中每个字符在s中最靠左与最靠右的匹配。
其实我们在之前检查t是否为s的子序列时,是从左至右贪心处理的,这样匹配的子序列一定是原串中最靠左的。试想如果提前从右至左贪心,则可预存每个t中字符在原串中最靠右的匹配位置。相邻字符,一左一右,这样我们就可以保证删去子串在满足条件的情况下最长。注意头尾特判。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 2e5 + 10; 5 char strS[maxn] , strT[maxn]; 6 int Rmost[maxn]; 7 int main(){ 8 scanf("%s%s",strS,strT); 9 int lenS = strlen(strS) , lenT = strlen(strT); 10 int ind = lenT - 1; 11 for (int i = lenS - 1; i >= 0; i--) { 12 if(strS[i] == strT[ind]){ 13 Rmost[ind] = i; 14 ind --; 15 } 16 if(ind == -1) break; 17 } 18 ind = 0; 19 int ans = Rmost[0]; // rm the Leftmost substring 20 // for(int i = 0;i < lenT;++i) printf("Rmost %d : %d ",i,Rmost[i]); 21 for (int i = 0; i < lenS; ++i) { 22 if(strS[i] == strT[ind]){ 23 if(ind == lenT - 1) ans = max(ans , lenS - 1 - i);// rm the Rightmost substring; 24 else ans = max(ans, Rmost[ind+1] - i - 1); 25 ind ++ ; 26 } 27 if(ind == lenT) break; 28 } 29 printf("%d ",ans); 30 return 0; 31 }
复杂度为O(n)。