http://codeforces.com/contest/762/problem/C
第一个串str[],第二个sub[]
预处理出prefix[i]表示sub的前i位和str[]的最长lcs去到str[]的最小的位置,如果某一位i不成立了,就设为inf
由于处理的时候,指针指向str[]的是单调递增的,所以预处理复杂度O(n),同样预处理suffix数组。
那么就是求一个位置,使得两个数组不会相交。
但是如果会相交,那么应该让那个数组退后一步呢,一开始用数组相邻差的绝对值来确定,因为移动得多的那个必定更优。
但是不然,test5就知道了。
于是乎就直接处理出所有的prefix[i],所对应的最优suffix[],这个可以在suffix[]中二分搞定。
话说二分可真有用。

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> vector<int>pos[26]; const int maxn = 1e5 + 20; char str[maxn], sub[maxn]; int lenstr, lensub; int L, R; int prefix[maxn]; int suffix[maxn]; void init() { int p1 = 0; for (int i = 1; i <= lensub; ++i) { if (pos[sub[i] - 'a'].size() == 0) break; if (pos[sub[i] - 'a'].back() <= p1) break; prefix[i] = upper_bound(pos[sub[i] - 'a'].begin(), pos[sub[i] - 'a'].end(), p1) - pos[sub[i] - 'a'].begin(); prefix[i] = pos[sub[i] - 'a'][prefix[i]]; p1 = prefix[i]; } // for (int i = 1; i <= lensub; ++i) { // cout << prefix[i] << " "; // } p1 = lenstr; for (int i = lensub; i >= 1; --i) { while (p1 >= 1) { if (str[p1] == sub[i]) break; p1--; } if (p1 == 0) break; suffix[i] = p1; p1--; } // for (int i = 1; i <= lensub; ++i) { // cout << suffix[i] << " "; // } } void work() { scanf("%s%s", str + 1, sub + 1); lenstr = strlen(str + 1); lensub = strlen(sub + 1); memset(prefix, 0x3f, sizeof prefix); memset(suffix, -1, sizeof suffix); for (int i = 1; i <= lenstr; ++i) { pos[str[i] - 'a'].push_back(i); } prefix[0] = -1; suffix[lensub + 1] = inf; init(); int pos1 = inf, pos2 = inf; for (int i = 1; i <= lensub; ++i) { if (prefix[i] == inf) { pos1 = i - 1; break; } } for (int i = lensub; i >= 1; --i) { if (suffix[i] == -1) { pos2 = i + 1; break; } } if (prefix[1] == inf && suffix[lensub] == -1) { cout << "-" << endl; return; } if (pos1 == inf || pos2 == inf) { cout << sub + 1 << endl; return; } if (pos1 == 0) { assert(pos2 != lensub + 1); for (int i = pos2; i <= lensub; ++i) { printf("%c", sub[i]); } return; } if (pos2 == lensub + 1) { for (int i = 1; i <= pos1; ++i) { printf("%c", sub[i]); } return; } int anslen = -1; for (int i = 0; i <= pos1; ++i) { int topos = upper_bound(suffix + pos2, suffix + 1 + lensub, prefix[i]) - suffix; // cout << suffix[topos] << endl; if (anslen < i + lensub - topos + 1) { anslen = i + lensub - topos + 1; L = i + 1; R = topos - 1; } } // cout << L << " " << R << endl; for (int i = 1; i <= lensub; ++i) { if (i == L) { i = R; continue; } printf("%c", sub[i]); } } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }