KMP字符串匹配 fzu2275重现赛POJ3167

KMP原理  点击

FZU 2275 Game

乍一看是个博弈的题目,实际上是重现里面比较简单的字符匹配。

只要B是0,那么A一定赢。只要A的长度小于B,那么B一定赢。

只有当A中可以搜索到B,也就是B或者B的反转是A的子串,那么A就可以赢。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
char a[N];
char b[N];
int next[N];
int n,m;
void getnext()
{
    memset(next, 0, sizeof(next));
    int n = strlen(b);
    int i = 0, j = -1;
    next[0] = -1;
    while(i < n)
    {
        if(j == -1 || b[i] == b[j])
        {
            i++, j++;
            if(b[i] == b[j])
                next[i] = next[j];
            else
                next[i] = j;
        }
        else
            j = next[j];
    }
}

int kmp()
{
    int n = strlen(a);
    int m = strlen(b);
    int i = 0, j = 0;

    while(i < n && j < m)
    {
        if(j == -1 || a[i] == b[j])
        {
            i++, j++;
        }
        else
            j = next[j];
    }
    if(j == m)
        return i-m;
    return -1;
}
int t;

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>a>>b;
        n =strlen(a);
        m = strlen(b);
        if(m == 1 && b[0] == ‘0‘)
        {
            printf("Alice\n");
            continue;
        }
        if(n < m)
        {
            printf("Bob\n");
            continue;
        }

        getnext();
        int res = kmp();
        if(res >= 0)
        {
            printf("Alice\n");
            continue;
        }

        reverse(b, b + m);
        getnext();
        res = kmp();
        if(res >= 0)
        {
            printf("Alice\n");
            continue;
        }

        printf("Bob\n");
        continue;

    }
    return 0;
}

上述是一个裸的KMP,POJ的这个是一个KMP的变形,就是改造判断条件。

题目要求是让 子串的各个序号的排名跟匹配串的排名一样,那么就算匹配成功,也就是说,对于每一个子串中的序号的数,

他前面的小于他的数的个数还有等于他的数的个数都要对应相等,把这个条件更换到KMP的条件就可以匹配了。

当时没做出来,参考了上海大学的模板,看懂后自己敲了一遍,雷同是有的。(KMP还有许多题,还有待练习

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5 + 5;

vector<int> ans;
int n, m, s;
int a[N], b[N];
int as[N][30], bs[N][30];
int next[N];

void init()
{
    memset(as, 0, sizeof(as));
    memset(bs, 0, sizeof(bs));

    as[1][a[1]] = 1;
    bs[1][b[1]] = 1;

    for(int i = 2; i <= n; i++)
    {
        memcpy(as[i], as[i-1], sizeof(as[i-1]));
        as[i][a[i]]++;
    }
    for(int i = 2; i <= m; i++)
    {
        memcpy(bs[i], bs[i-1], sizeof(bs[i-1]));
        bs[i][b[i]]++;
    }
}

void getnext()
{
    int i = 1;
    int j = 0;
    int si,sj,ei,ej;
    next[1] = 0;

    while(i <= n)
    {
        si = sj = ei = ej = 0;

        for(int k = 1; k < b[i]; k++)
        {
            si += bs[i][k] - bs[i-j][k];
        }
        ei = bs[i][b[i]] - bs[i-j][b[i]];

        for(int k = 1; k < b[j]; k++)
        {
            sj += bs[j][k];
        }
        ej = bs[j][b[j]];

        if(j == 0 || (si == sj && ei == ej))
        {
            i++, j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

void kmp()
{
    int i = 1, j = 1;
    int si, sj, ei, ej;

    while(i <= n)
    {
        si = sj = ei = ej = 0;

        for(int k = 1; k < a[i]; k++)
        {
            si += as[i][k] - as[i-j][k];
        }
        ei = as[i][a[i]] - as[i-j][a[i]];

        for(int k = 1; k < b[j]; k++)
        {
            sj += bs[j][k];
        }
        ej = bs[j][b[j]];

        if(j == 0 || (si == sj && ei == ej))
        {
            i++, j++;
        }
        else
            j = next[j];

        if(j == m+1)
        {
            ans.push_back(i - m);
            j = next[j];
        }
    }
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &s) != EOF)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= m; i++)
            scanf("%d", &b[i]);

        init();
        ans.clear();
        getnext();
        kmp();
        printf("%d\n", ans.size());
        for(int i = 0; i < ans.size(); i++)
            printf("%d\n", ans[i]);
    }
    return 0;
}
时间: 2024-10-27 10:28:41

KMP字符串匹配 fzu2275重现赛POJ3167的相关文章

Luogu P3375 【模板】KMP字符串匹配

P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数

KMP字符串匹配

1 #include<iostream> 2 3 4 using namespace std; 5 6 #define MAX 255 7 8 typedef unsigned char BYTE; 9 10 typedef BYTE String[MAX+1]; 11 12 bool strAssign(String& strTemp,char* Temp); //定长字符串存储 13 bool strTravel(String& strTemp); //打印 14 void

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整

P3375 模板 KMP字符串匹配

P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; int n, m; char s1[N], s2[N]; int nxt[N] ; void Get_next(char *s) { int j, L = strlen(s + 1); nxt[1] = j = 0; for(int i = 2; i

FZU 2122 ——又见LKity——————【KMP字符串匹配】

Problem 2122 又见LKity Accept: 413    Submit: 1425Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 嗨!大家好,在TempleRun中大家都认识我了吧.我是又笨又穷的猫猫LKity.很高兴这次又与各位FZU的ACMer见面了.最近见到FZU的各位ACMer都在刻苦地集训,整天在日光浴中闲得发慌的我压力山大呀!于是,我准备为诸位编写一款小工具——LKity牌文本替

【洛谷】3375 KMP字符串匹配

[算法]KMP [题解][算法]字符串 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1000010,maxm=1010; char A[maxn],B[maxm]; int p[maxm],n,m; int main() { scanf("%s%s",A+1,B+1); n=strlen(A+1);m=strlen

洛谷—— P3375 【模板】KMP字符串匹配

题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值. 输

算法模板——KMP字符串匹配

功能:输入一个原串,再输入N个待匹配串,在待匹配串中找出全部原串的起始位置 原理:KMP算法,其实这个东西已经包含了AC自动机的思想(fail指针/数组),只不过适用于单模板匹配,不过值得一提的是在单模板大量匹配待匹配串时,这个会有相当大的优势,AC自动机虽然好想一些,但是在这一类问题上的性价比就略低了 1 var 2 i,j,k,l,m,n:longint; 3 a:array[0..100000] of longint; 4 s1,s2:ansistring; 5 begin 6 readl

P3375 【模板】KMP字符串匹配(全程注释,简单易懂)

题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值. 输