[CF762C] Two Strings(预处理,二分答案)
题目链接:http://codeforces.com/contest/762/problem/C
题意:两个字符串a、b。希望在a中删掉连续的字符串,使得b是a的子序列。
希望删掉的是连续的字符串,那么可以预处理两个数组pre和suf。
pre(i)表示b[0,i]为a的子序列,a的最短长度。
suf(i)表示b[i,na)为a的子序列,a倒着数的最短长度。
会发现这两个数列是单调的,二分答案len,表示中间删掉的字符串长度为len。O(n)枚举a删除的起始点,判断即可。
注意判断时枚举到起点为0,即无前缀的时候,要判断这时后缀长度是否满足条件。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 100100; 5 char a[maxn], b[maxn]; 6 int na, nb; 7 int pre[maxn], suf[maxn]; 8 bool exflag; 9 string ret; 10 11 bool ok(int len) { 12 for(int i = 0; i <= nb-len; i++) { 13 if((i == 0 && suf[len] >= 0) || pre[i-1] < suf[i+len]) { 14 ret = ""; 15 exflag = 1; 16 for(int j = 0; j < i; j++) ret += b[j]; 17 for(int j = i+len; b[j]; j++) ret += b[j]; 18 return 1; 19 } 20 } 21 return 0; 22 } 23 24 int main() { 25 // freopen("in", "r", stdin); 26 memset(a, 0, sizeof(a)); 27 memset(a, 0, sizeof(b)); 28 while(~scanf("%s%s",a,b)) { 29 na = strlen(a); nb = strlen(b); 30 memset(pre, 0, sizeof(pre)); 31 memset(suf, 0, sizeof(suf)); 32 int p = 0; 33 for(int i = 0; i < nb; i++, p++) { 34 while(p < na && a[p] != b[i]) p++; 35 pre[i] = p; 36 } 37 p = na - 1; 38 for(int i = nb-1; i >= 0; i--, p--) { 39 while(p >= 0 && a[p] != b[i]) p--; 40 suf[i] = p; 41 } 42 suf[nb] = na; 43 // for(int i = 1; i <= nb; i++) printf("%d ", pre[i]); printf("\n"); 44 // for(int i = 1; i <= nb; i++) printf("%d ", suf[i]); printf("\n"); 45 exflag = 0; ret = ""; 46 int lo = 0, hi = nb - 1; 47 while(lo <= hi) { 48 int mid = (lo + hi) >> 1; 49 if(ok(mid)) hi = mid - 1; 50 else lo = mid + 1; 51 } 52 if(!exflag) puts("-"); 53 else cout << ret << endl; 54 memset(a, 0, sizeof(a)); 55 memset(a, 0, sizeof(b)); 56 } 57 return 0; 58 }