Codeforces Round #106 (Div. 2) 149/E E. Martian Strings

/*
  http://codeforces.com/problemset/problem/149/E
  KMP结合动态规划的思想,正向匹配一边,l[]数组保存的是对于匹配串的每一个位置在模式串能匹配的最左边,也就是首次匹配的位置
  逆序再匹配一次,逆向信息保存r[]数组。
  再枚举l[i]+r[len-i]
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = 1005;
const int inf = maxn*maxn+1;
int next[maxn];
char word[maxn];
char test[maxn*maxn];
char test_reverse[maxn*maxn];
int l[maxn],r[maxn];
void getnext(char str[]){
    int i = 0,j = -1;
    int len = (int)strlen(str);
    next[0] = -1;
    while(i < len){
        if(j == -1 || str[i] == str[j]){
            ++i,++j;
            if(str[i] == str[j])
                next[i] = next[j];
            else
                next[i] = j;
        }
        else
            j  = next[j];
    }
}
void kmp(char str[],char pat[],int dp[]){
    int i = 0,j = 0;
    getnext(pat);
    int len_str = (int)strlen(str);
    int len_pat = (int)strlen(pat);
    while(i < len_str&&j < len_pat){
        if(j == -1 || str[i] == pat[j]){
            i++;
            j++;
            dp[j] = min(dp[j],i);
        }
        else
            j = next[j];
        if(j == len_pat)
            j = next[j];
    }
}
void init(int len){
    l[0] = 0,r[0] = 0;
    for(int i = 1;i <= len;i++){
        l[i] = inf;
        r[i] = inf;
    }
}

int main(){

    while(~scanf("%s",test)){
        int len = (int)strlen(test);
        for(int i=0;i<len;i++)
            test_reverse[i]=test[len-1-i];
        int m;
        scanf("%d",&m);
        int ans = 0;
        while(m--){
            scanf("%s",word);
            int len_word = (int)strlen(word);
            if(len_word==1) continue;
            init(len_word);
            kmp(test,word,l);
            reverse(word, word+strlen(word));
            kmp(test_reverse, word, r);
            //for(int i = 0;i < strlen(word);i++)
              //  printf("%d %d\n",l[i],r[i]);
            for(int i = 1;i <= len_word;i++){
                if(l[i] + r[len_word - i] <= len){
                    ans++;
                    break;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值