pipioj 1039 重复子序列问题

题目描述

1039

PIPI有两个字符串A和B,请你求出字符串A最少重复几次才能使得B是A的子序列。

我们称X是Y的子序列当且仅当可以从Y中删除若干个字符得到X。

例如对于A=“abb”, B=“bbaa”,则A重复3次之后得到"abbabbabb",此时B="bbaa"是"abbabbabb"的子序列。

注意,原始串A即算作重复一次。

输入

多组数据。

第一行包含一个字符串A。

第二行包含一个字符串B。

A和B都只包含小写字母。

对于30%的数据,1 <= |A|, |B| <= 100

对于90%的数据,1 <= |A|, |B| <= 1000

对于100%的数据,1 <= |A|, |B| <= 100000
输出
一个整数代表答案。如果无论重复多少次都达不到,输出-1。

样例输入

abb
bbaa

样例输出

3

一开始直接暴力搜索,由于字符串可能过长直接超时了。

B中字符需为A中字符的子集,当某个字符B有而A无则无法完成,返回-1。
然后就存储各种字符以及他的位置,找到字符后在他的位置序列中选取比上一个字符位置稍大的。
如果没有比他大的则选取最小的。
返回位置与上一个字符位置比较,如果前者小于或等于后者表明需要重复一次。反之,无需重复。

#include 
#include 
#include 
using namespace std;

struct ch{
   char c;
   int len;
   int locat[100005];
}ch[26];
int b[26],lena,lenb;
char A[100005],B[100005];
int getlocat(int len,char c,int p){
int i;
for(i=0;i<len;i++)
    if(ch[i].c==c) break;
int left=0,right=ch[i].len-1,mid,l=-1;

if (p==-1)return ch[i].locat[0];
while(left<=right){
    l=mid=(left+right)/2;
    if(ch[i].locat[mid]==p) {break;}
    if(ch[i].locat[mid]<p) left=mid+1;
    else if(ch[i].locat[mid]>p) right=mid-1;
};
//printf("l,,,%d\n",ch[i].locat[l]);
if(ch[i].locat[l]<=p) l=(l+1)%ch[i].len;
return ch[i].locat[l];
}
int main(){
    int i,flag,chlen;
while(scanf("%s",A)!=EOF){
    scanf("%s",B);flag=0;
    memset(b,0,sizeof(b));
    lena=strlen(A);
    lenb=strlen(B);
    for(i=0;i<26;i++) ch[i].len=0;
    for(i=0;i<lena;i++) {ch[A[i]-'a'].locat[ch[A[i]-'a'].len]=i;ch[A[i]-'a'].c=A[i];ch[A[i]-'a'].len+=1;}
    for(i=0;i<lenb;i++) b[B[i]-'a']++;
    for(i=0;i<26;i++) if((!ch[i].len)&&b[i]) {flag=1;break;}
    if(flag) {printf("-1\n");continue;}
    int k=0;
    for(i=0;i<26;i++)
        if(ch[i].len==0) k++;
     else if(k!=0) ch[i-k]=ch[i];
    int pa=-1,pb=0,p,ans=0;
    while(pb<lenb){
            p=getlocat(26-k,B[pb++],pa);
           // printf(" %d %d\n",pa,p);
        if(p<=pa||pa==-1) ans++;
        pa=p;
    }
    printf("%d\n",ans);
}
}

你可能感兴趣的:(pipioj 1039 重复子序列问题)