密码

密码(子序列)

给你一个加密后的字符串,一个加密前的字符串,问有多少种方法,使得加密后的字符串从两边切割后,包含加密前字符串的子序列。

既然是要求切割方法,肯定要考虑重复情况。我们枚举切割的左端点,然后找到包含未加密字符串的最短子序列的右端点,然后统计答案即可。

#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const LL maxn=3e5+5, maxm=205;
LL len1, len2, ans;
LL right[maxn][26];
char s1[maxn], s2[maxm];

void preprocess(){
    for (LL j=0; j<26; ++j){
        right[len1][j]=-2;
        right[len1-1][j]=-2;
    }
    right[len1-1][s1[len1-1]-'a']=len1-1;
    for (LL i=len1-2; i>=0; --i)
        for (LL j=0; j<26; ++j)
            if (s1[i]-'a'==j) right[i][j]=i;
            else right[i][j]=right[i+1][j];
}

int main(){
    scanf("%s%s", s1, s2);
    len1=strlen(s1); len2=strlen(s2);
    preprocess(); LL j, k;
    for (LL i=0; i<len1; ++i){
        k=i;
        for (j=0; j<len2; ++j){
            if (!~k) break;
            k=right[k][s2[j]-'a']+1;
        }
        if (~k) ans+=len1-k+1;
    }
    printf("%lld", ans);
    return 0;
}
posted @ 2017-11-01 11:29  pechpo  阅读(168)  评论(0)    收藏  举报