kmp小题集

kmp的部分题目及求解算法;
已经了解kmp的朋友门欢迎加入哦(仅为个人所做的题目;未对kmp算法进行讲解)
以下为:输入输出样例+翻译解释+代码+代码解析
本宝宝也是初学者。。。。很高兴朋友们指点呀;

1---------------------------------------------------
Input
The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:

One line with the word W, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
One line with the text T, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with |W| ≤ |T| ≤ 1,000,000.
Output
For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.

Sample Input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample Output
1
3
0

翻译就是求A串在B串循环的次数

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int sum=0;
char s[1000001],p[1000001];
int nx[1000001];
void getnext(char *p,int nx[])//next数组
{
    nx[0]=-1;
    int i=0,j=-1;
    int r=strlen(p);
    while(i<r)
    {
        if(j==-1||p[i]==p[j])
        {
            j++,i++;
            nx[i]=j;
>   }
        else
            j=nx[j];
    }
}
void kmp(char *s,char *p)//是否匹配
{
    int l1=strlen(s);
    int l2=strlen(p);
    int i=0,j=0;
    getnext(p,nx);
    while(i<l1)
    {
        if(j==-1||s[i]==p[j])
        {
            i++;
            j++;
            if(j==l2)
            {
                sum++;
                j=nx[j];
            }

        

}
        else
            j=nx[j];


    }
}
int main()
{
    int n,i,j;
    scanf("%d",&n);

    while(n--)
    {
        scanf("%s%s",p,s);//c++可以这样输入;p:模板串,s:主串;
        sum=0;
        kmp(s,p);
        printf("%d\n",sum);
    }
    return 0;
}

2---------------------------------------------------------------------
Input
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
Output
For each s you should print the largest n such that s = a^n for some string a.
Sample Input
abcd
aaaa
ababab
.
Sample Output
1
4
3

翻译就是求一个串的循环次数;

//代码参考大佬的;(不过我加注释了;)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int L=1001001;//**等价于#define L 1001001
int l,nt[L];
char s[L];

void Make_nt()
{
    int i=0,j=-1;
    nt[i]=-1;
    while(i<l)
    {
        if(j==-1||s[i]==s[j])
            ++i,++j,nt[i]=j;
        else j=nt[j];
    }
}

int main()
{
    int len,Ans;
    for(scanf("%s",s); s[0]!='.'; scanf("%s",s))//可以体现对for循环的充分理解;
    {
        l=strlen(s);
        Make_nt();
    //   for(int i=0;i<=l;i++)
   //    {
     //      printf("%d ",nt[i]);
      // }
      // printf("\n");
        Ans=1;
        if(l%(l-nt[l])==0) Ans=l/(l-nt[l]);//nt[0]=-1,nt数组值以次向后挪一位;排除了aaa,但nt[3]=2的情况;
        printf("%d\n",Ans);
    }
    return 0;
}


3------------------------------------------------------------------------------------------------

Given two sequences of numbers : a[1], a[2], … , a[N], and b[1], b[2], … , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], … , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one.
Input
The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], … , a[N]. The third line contains M integers which indicate b[1], b[2], … , b[M]. All integers are in the range of [-1000000, 1000000].
Output
For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead.
Sample Input
2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1
Sample Output
6
-1

翻译就是B串在A串中出现的最开始的下标(从1开始);若不曾出现返回-1;

#include<bits/stdc++.h>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const LL maxn = 1e6+10;//等价于1000010;1e6=1*10^6;
int s1[maxn], s2[maxn], n, m;
int nxt[maxn];
void getNext()
{
    int i = 1, j = 0;
    while(i < m)
    {
        if(j==0 || s2[i]==s2[j])
        {
            ++i, ++j;
            nxt[i] = j;
        }
        else j = nxt[j];

    }

}
int kmp()
{
    getNext();
    int i = 1, j = 1;
    while(i <= n && j <= m)//前提要保证i<=n;否则便会陷入一个死循环
    {
        if(s1[i]==s2[j] || j==0)
            ++i, ++j;
        else j = nxt[j];
    }
    if(j > m) return i - m;
    else return -1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ms(s1, 0);//每次重置为0;
        ms(s2, 0);
        ms(nxt, 0);
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
            scanf("%d",&s1[i]);
        for(int j = 1; j <= m; j++)
            scanf("%d",&s2[j]);
        printf("%d\n",kmp());
    }
    return 0;
}

4 Count the string

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: “abab”
The prefixes are: “a”, “ab”, “aba”, “abab”
For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.
Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.
Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.
Sample Input
1
4
abab
Sample Output
6

题意:对于每个前缀,我们可以计算它在s中匹配的次数,这样我们可以看到前缀“a”匹配两次,“ab”匹配两次,“aba”匹配一次,“abab”匹配一次。现在要求您计算所有前缀的匹配时间之和。对于“abab”,它是2+2+1+1=6。

答案可能很大,所以输出答案mod 10007。

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
#define end '\n'
#define IOS ios::sync_with_stdio(0)
int nxt[N],len=0,dp[N],mod=10007;
void get_next(string p) {
    int j = 0, k = -1;
    nxt[0] = -1;
    while (j < len)
        if (k == -1 || p[j] == p[k])
            nxt[++j] = ++k;
        else
            k = nxt[k];
}
int main() {
    string a;
    IOS;
    int t;
    cin >> t;
    while (t--) {
        cin >> len;
        cin >> a;
        get_next(a);
        memset(dp, 0, sizeof(dp));
        int sum = 0;
        for (int i = 1; i <= len; i++) {
            dp[i] = dp[nxt[i]] + 1;
            cout<<dp[i]<<"  "<<nxt[i]<<end;
            sum = (sum + dp[i]) % mod;
        }
        cout << sum << end;
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值