Educational Codeforces Round 17 C && codeforces 762C C. Two strings 详细的题解 (前后缀应用)

来源:互联网 发布:java中局部变量 编辑:程序博客网 时间:2024/05/31 06:23


C. Two strings
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given two strings a and b. You have to remove the minimum possible number of consecutive (standing one after another) characters from string b in such a way that it becomes a subsequence of string a. It can happen that you will not need to remove any characters at all, or maybe you will have to remove all of the characters from b and make it empty.

Subsequence of string s is any such string that can be obtained by erasing zero or more characters (not necessarily consecutive) from string s.

Input

The first line contains string a, and the second line — string b. Both of these strings are nonempty and consist of lowercase letters of English alphabet. The length of each string is no bigger than 105 characters.

Output

On the first line output a subsequence of string a, obtained from b by erasing the minimum number of consecutive characters.

If the answer consists of zero characters, output «-» (a minus sign).

Examples
input
hibob
output
-
input
abcaaccepted
output
ac
input
abacabaabcdcba
output
abcba
Note

In the first example strings a and b don't share any symbols, so the longest string that you can get is empty.

In the second example ac is a subsequence of a, and at the same time you can obtain it by erasing consecutive symbols cepted from string b.


题意:两个字符串 s1 s2 长度1e5 ,问题 串2 去掉一个最短连续子串,使得剩下的串拼起来是 串1 的一个子串。

首先要理解题意,这个题是删除 一段 连续 的子串,串b的三部分都是连续的,问剩下的两串拼起来是不是串1的一个子串,如果最暴力的枚举删除的区间o(n3)复杂度。。肯定不行,这里学习了前缀后缀不一定只是记录某个数的和的,也可以像这个题这么用。。

思路:记录串a每个字符,是串b最长的属于串a这个字符之前的子序列坐标的最后一个,比如  串a : ababa 串 b: abc, 那么pre【1】 = 1pre【2】 = 2, pre【3】 = 2, pre【4】 = 2 ,pre【3】= 2指的是 串b 中 ab 是串a前三个的字符的子序列,同理记录串a的后缀,这样的目的是,很方便的知道每个字符 往前对应几个b 往后对应几个b,要删除的那一串字符就是 suf - pre,不用暴力枚举了,这里因为这三个串都是连续的所以可以这样前缀后缀,在suf-pre的时候,有的题解是二分来找,其实不用,因为是前缀,pre【i+1】 肯定 >= pre[i],suf[i-1] >= suf[i],而且又要求是最短的所以suf[i] - pre[i-1]肯定是最短的,枚举i的时候,pre【i-1】肯定是前i个最大的。。所以直接-pre【i-1】就行。。

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;const int maxn = 1e5 + 5;int pre[maxn], suf[maxn];char a[maxn], b[maxn];int main(){    while(~scanf("%s", a+1))    {        scanf("%s", b+1);        int l1 = strlen(a+1), l2 = strlen(b+1), last = 0;  //这一步很重要,这里是预防,串1还没枚举玩,串b已经枚举完了,串b枚举完了,代表还没有枚举的串1前缀都是串b最后一个,后缀都是串1第一个        for(int i = 1; i <= l1; i++)            pre[i] = l2, suf[i] = 1;        suf[l1+1] = l2+1; //这个是为了找删去最短子串做准备,因为是-pre【i-1】,所以要枚举到l2+1        for(int i = 1, j = 1; i <= l1 && j <= l2; i++)  //这里是构造前缀        {            if(a[i] == b[j])                pre[i] = j, last = j, j++;  //如果相同,就看下一个串b的字符,更新last            else                pre[i] = last;  //如果这个不相同,就等于前面的last        }        last = l2+1;  //这里的初始化是l2+1,代表后缀是比l2的长度多1,也就是没有一个相同的        for(int i = l1, j = l2; i >= 1 && j >= 1; i--)        {            if(a[i] == b[j])                suf[i] = j, last = j, j--;            else                suf[i] = last;        }        int ans = l2+1, l, r;  //ans 初始化时l2+1,因为suf最多是l2+1(代表一个相同的也没有),pre最小是0(代表一个相同的也没有),ans = suf - pre 所以最大就是l2+1//        cout << ans << endl;        for(int i = 1; i <= l1+1; i++)  //这里是枚举删除的最短的字符串,记住要枚举到l1+1,因为-pre【i-1】        {//            cout << suf[i] << ' ' << pre[i-1] << endl;            if(pre[i-1] < suf[i]) //枚举suf【i】,pre【i-1】肯定是前i-1个中最大的,所以直接-它就行,而且首先要确保pre[i-1] < suf[i],因为这样才能“删除”            {                if(ans > suf[i]-pre[i-1])  //这里是更新                {                    ans = suf[i] - pre[i-1];//                    cout << suf[i] << ' ' << pre[i-1] << endl;                    l = pre[i-1];  //这是记录删除子串的位置                    r = suf[i];                }            }        }        if(ans == l2+1)  //如果没有更新过就输出        {            cout << "-" << endl;            continue;        }        for(int i = 1; i <= l2; i++)  //输出没删除的子串        {            if(i <= l || i >= r)                cout << b[i];        }    }    return 0;}

这个题很好,没有做过很多题,很好的代码素养,一般是做不出来的吧。。。第一次了解到前后缀的这种应用,记录的是另一个串的下标。。cf总有一些黑科技~



1 0
原创粉丝点击