1. 程式人生 > >FJUT OJ 2584 QAQ的變強魔咒(KMP)

FJUT OJ 2584 QAQ的變強魔咒(KMP)

scan input 分割 pre next 小寫字母 先後 ace void

突然有一天默默無聞的QAQ變成了FJUTOJ的終極大BOSS,而使得QAQ變強的是QAQ掌握有一個由小寫字母組成魔咒。

作為QAQ小弟的V_Dragon偷偷的聽到了一部分連續魔咒,V_Dragon非常的激動,因為這一部分魔咒能使得菜雞V_Dragon

變強100倍。但V_Dragon的聽力不是很好,有一些聽不清,也有可能聽錯。但V_Dragon有個神奇的魔法,可以將他沒聽

清的部分變成QAQ魔咒中的任意部分(也可以為空),現在要聰明的ACMer你來判斷V_Dragon有沒有聽錯。

(題目沒看懂? 沒關系,看樣例!!)

Input

輸入包含多組測試數據

輸入第一行表示QAQ掌握的魔咒,1<=s1<=100000,只包含小寫字母

輸入第二行表示V_Dragon偷聽到的魔咒,1<=s2<=100000,‘*‘表示V_Dragon沒聽清的部分。只包含小寫字母和‘*‘

Output

判斷V_Dragon是否聽錯。沒聽錯輸出YES,聽錯輸出NO

SampleInput
abcdef
a*b*e
abcdef
a*c*f
abcdef
ac*f
abc
bc
SampleOutput
YES
YES
NO
YES
提示:
樣例1:第一個‘*‘表示一個空串,第二個‘*‘表示cd,變成abcde是魔咒的子串
樣例2:第一個‘*‘表示b,第二個‘*‘表示de,變成abcdef是魔咒的子串
樣例3:‘*‘不管代表什麽都可能是魔咒的子串,所以V_Dragon肯定聽錯了
樣例4:懶得解釋

分析:在字符串2中,我們可以看成它是由*分割的幾個字符串.如果要符合要求,那麽這幾個字符串就一定會按照順序在串1中出現,
所以我們把這幾個由*分割的字符串與串1進行KMP操作,找到它在串1中出現,並且滿足先後順序要求的第一個位置。
如果串2中所有的由*分割的字符串都能找到這樣的位置 就輸出 YES 否則輸出NO
要特別註意的是 由單個和多個*號組成的串2 都輸出YES
代碼如下:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1000002;
int Next[N];
char S[N], T[N];
char r[N];
int slen, tlen;//註意每次一定要計算長度
int rlen;
int left1;
int right1;
void getNext()
{
    int j, k;
    j = 0; k = -1; Next[0] = -1;
    while(j < tlen)
        
if(k == -1 || T[j] == T[k]) Next[++j] = ++k; else k = Next[k]; } /* 返回模式串T在主串S中首次出現的位置 返回的位置是從0開始的。 */ int KMP_Index() { int i = 0, j = 0; getNext(); while(i < slen) { if(j == -1 || S[i] == T[j]) { i++; j++; } else j = Next[j]; if(j == tlen){ if(i-tlen>left1) return i - tlen; j=Next[tlen]; } } return -1; } int main() { int TT; int i, cc,cnt,flag; scanf("%d",&TT); while(scanf("%s",S)!=EOF) { flag=1; scanf("%s",r); slen = strlen(S); rlen=strlen(r); r[rlen]=*; rlen++; r[rlen]=0; cnt=0; left1=-1; for(int i=0;i<rlen;i++) { if(r[i]!=*) { T[cnt++]=r[i]; continue; } else { if(cnt==0)continue; T[cnt]=0; tlen=cnt; right1=KMP_Index(); if(right1<=left1) { flag=0; break; } else{ left1=right1; cnt=0; } } } flag==1?puts("YES"):puts("NO"); } return 0; }



FJUT OJ 2584 QAQ的變強魔咒(KMP)