2019安徽省程序设计竞赛 I.你的名字(序列自动机)

这题和今年南昌邀请网络预选赛M题很像啊,不过主串数量不是一个了

都是在主串中判断子串是不是属于主串的一个子序列

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

const int maxn = 1000 + 5;
const int maxm = 30 + 5;
char s1[maxn], s2[maxm];
int Next[maxn][maxn][26], last[26], ans[maxn];
int n, m;
int main(){
    // freopen("in.txt", "r", stdin);    //输入文件里最后一行后要加回车,不然会死循环
    scanf("%d%d", &n, &m);
    getchar();
    memset( ans, 0, sizeof(ans) );
    memset( Next, -1, sizeof(Next) );
    for( int i=0; i<n; i++ ){
        char ch, tot = 0;
        while( (ch=getchar())!='\n' ){
            if( ch>='A' && ch<='Z' ) ch += 'a'-'A';
            s1[++tot] = ch;
        }
        s1[++tot] = 0;
        memset( last, 0, sizeof(last) );
        for( int j=1; j<tot; j++ ){
            int id = s1[j]-'a';    
            for( int k=j-1; k>=last[id]; k-- ) Next[i][k][id] = j;    //Next数组存第i个主串k位置后第一个id字符所在的位置
            last[id] = j;
        }
    }
    for( int i=0; i<m; i++ ){        //输入进来每个模式串
        char ch, tot=0;
        while( (ch=getchar())!='\n' ){
            if( ch>='A' && ch<='Z' ) ch += 'a'-'A';
            s2[tot++] = ch;
        }
        s2[tot] = 0;
        for( int j=0; j<n; j++ ){    //对每个主串进行匹配
            int pos = 0;
            bool ok = 1;
            for( int k=0; k<tot; k++ ){
                int id = s2[k]-'a';
                if( Next[j][pos][id]!=-1 ) pos = Next[j][pos][id];    //如果成功继续匹配下一字符
                else{            //匹配不成功,即该字符在pos后没有出现,则break
                    ok = 0;    
                    break;
                }
            }
            if( ok ) ans[j] ++;    //每个主串成功匹配一个模式串后价值数+1
        }
    }
    for( int i=0; i<n; i++ ) printf("%d\n", ans[i]);    //逐个输出

    return 0;
}

 

posted @ 2019-05-23 00:23  CoffeeCati  阅读(1587)  评论(0编辑  收藏  举报