Two strings CodeForces

来源:互联网 发布:java的布尔类型 编辑:程序博客网 时间:2024/06/02 04:14

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 10^5 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).

Example

Input
hi
bob
Output
-
Input
abca
accepted
Output
ac

Input
abacaba
abcdcba
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,你可以删除s2中连续的一段字符,使得剩下的s2串拼接起来成为s1的子序列串。如果存在,输出拼接后s2最长的那种情况,否则将s2串删光,输出-。

思路:假设我们要删除的连续字符的长度为len,len的范围为0到l2(s2串的长度)。可以很容易的看出len具有单调性,所以我们可以二分len,然后枚举所要删除的连续字符的起点,这样的话时间复杂度为nlogn,然后考虑怎么check,如果每次都直接暴力去判断的话那么需要o(n)的时间复杂度,这样总的时间复杂度就达到了n^2logn,T掉了。考虑到每次删完剩下的两段可以看作是s2串的前缀和后缀,所以我们可以先预处理出s2的所有前缀在s1串中最靠前的子序列的末尾位置a,和s2的所有后缀在s1串中最靠后的子序列的开头位置b,存到两个数组中,每次只需比较前者和后者的位置a,b是否满足a < b即可。这样check的时间复杂度就降到了O(1),总的时间复杂度为nlogn。

代码如下

#include <iostream>  #include <cstdio>  #include <cstring>  #include <cmath>  #include <algorithm>#include <vector>#include <map>#include <bitset>using namespace std;  const int maxn=1e5+5;#define ll long long int char s1[maxn],s2[maxn];int bef[maxn],nex[maxn];//前缀,后缀。int l1,l2;int ans1,ans2;//分别记录删除的起点和长度int check(int len){    for(int i=0;i<=l2-len;i++)    {        if(i==0)//特判一下如果从第一个就开始删        {            if(nex[len]>=0)//此时只要后缀满足是s1的子序列就可以了            {                ans1=0;                ans2=len;                return 1;             }         }        else        {            if(bef[i-1]<nex[i+len])//否则需要满足前缀位置小于后缀位置            {                ans1=i;                ans2=len;                return 1;             }         }     }    return 0;}int main()  {      gets(s1);    gets(s2);    l1=strlen(s1);    l2=strlen(s2);    int j=0;    for(int i=0;i<l2;i++)//前缀     {        while(1){            if(j==l1)//如果此时的前缀不是s1的子序列,则赋值为l1,判断的时候必将会大于后缀位置            {                bef[i]=j;                break;            }            if(s2[i]==s1[j])            {                bef[i]=j;                j++;                break;            }            j++;        }    }    j=l1-1;    for(int i=l2-1;i>=0;i--)//后缀     {        while(1){            if(j==-1)//如果此时的后缀不是s1的子序列,则赋值为-1,判断的时候必将会小于前缀位置            {                nex[i]=j;                break;            }            if(s2[i]==s1[j])            {                nex[i]=j;                j--;                break;            }            j--;        }    }    nex[l2]=l1;//可能会把后缀删光    int l=0,r=l2-1;    ans1=-1;    while(r>=l)    {        int mid=(r+l)/2;        if(check(mid))        {            r=mid-1;        }        else        l=mid+1;    }    if(ans1==-1)    printf("-\n");    else     {        for(int i=0;i<ans1;i++)        printf("%c",s2[i]);        for(int i=ans1+ans2;i<l2;i++)        printf("%c",s2[i]);    }    return 0;  }  
原创粉丝点击