1. 程式人生 > >寒假集訓——KMP

寒假集訓——KMP

此文章是集訓題目的解題報告,另外自己網上找了一些KMP的題目做做。

KMP簡單應用

Time Limit: 1000MS Memory limit: 65536K

題目描述

給定兩個字串string1和string2,判斷string2是否為string1的子串。

輸入

 輸入包含多組資料,每組測試資料包含兩行,第一行代表string1(長度小於1000000),第二行代表string2(長度小於1000000),string1和string2中保證不出現空格。

輸出

 對於每組輸入資料,若string2是string1的子串,則輸出string2在string1中的位置,若不是,輸出-1。

示例輸入

abc
a
123456
45
abc
ddd

示例輸出

1
4
-1

提示

解題報告

關於KMP報告在上一篇文章寫了,這邊就不詳細寫了,這題因為是用KMP來解的,所以資料很大,要注意的地方就是在迴圈的時候不能用strlen函式,不然每次迴圈都會耗掉呼叫函式的時間。。。

#include<stdio.h>
#include<string.h>
int next[1000010];
char T[1000010],B[1000010];
void getNext()//next陣列
{
    int m=strlen(B);
    int i=0,j=-1;
    next[0]=-1;
    while(i<m)
    {
        if(j==-1||B[i]==B[j])
        {
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int kmp()//KMP演算法
{
    getNext();
    int n=strlen(T),m=strlen(B);
    int i=0,j=0;
    while(i<n&&j<m)
    {
        if(j==-1||T[i]==B[j])
        {
            i++;j++;
        }
        else j=next[j];
    }
    if(j==m)
        return i-m+1;
    else return -1;

}
int main()
{
    while(scanf("%s%s",T,B)!=EOF)
    {
        printf("%d\n",kmp());
    }
    return 0;
}


Power Strings

Time Limit: 1000MS Memory limit: 65536K

題目描述

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

輸入

 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.

輸出

 For each s you should print the largest n such that s = a^n for some string a.

示例輸入

abcd
aaaa
ababab
.

示例輸出

1
4
3

提示

This problem has huge input, use scanf instead of cin to avoid time limit exceed. 解題報告

題目的意思是一個字串能用若干連續子串組成,也就是迴圈節問題,求最大迴圈節,如ababab的迴圈節ab,最大3個。。。

這題目是運用KMP演算法中的next陣列來解題,next陣列是部分匹配表,它是記錄字串字首和字尾的最長的公共子串長度。

#include<stdio.h>
#include<string.h>
int next[1000010];
char B[1000010];
void getNext()
{
    int i=0,j=-1;
    next[0]=-1;
    int l=strlen(B);
    while(i<l)
    {
        if(j==-1||B[i]==B[j])
        {
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}/*
void getNextval()
{
    int i=1,j=0;
    next[1]=0;
    int l=strlen(B);
    while(i<=l)
    {
        if(j==0 || B[i]==B[j])
        {
            ++i;++j;
            if(B[i]!=B[j]) next[i]=j;
            else next[i]=next[j];
        }
        else j=next[j];
    }
}*/
int main()
{
    int i,j,f;
    while(~scanf("%s",B))
    {
        if(B[0]=='.')break;
        int l=strlen(B);

        getNext();//for(int i=1;i<=l;i++)printf("%d",next[i]);
        //printf("\n");
        if(l%(l-next[l])==0)printf("%d\n",l/(l-next[l]));
        else printf("1\n");
    }
}

Period

Time Limit: 1000MS Memory limit: 65536K

題目描述

For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 ≤ i ≤ N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as AK , that is A concatenated K times, for some string A. Of course, we also want to know the period K.

輸入

 The input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it.

輸出

 For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.

示例輸入

3
aaa
12
aabaabaabaab
0

示例輸出

Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4
解題報告 這題就是在上一題進行變化,貼程式碼。。。PE一次。。。
#include<stdio.h>
#include<string.h>
int next[1000010],n;
char B[1000010];
void getNext()
{
    int i=0,j=-1;
    next[0]=-1;
    int l=strlen(B);
    while(i<l)
    {
        if(j==-1||B[i]==B[j])
        {
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int main()
{
    int i=1;
    while(scanf("%d",&n)!=EOF&&n)
    {
        //getchar();
        scanf("%s",B);
        getNext();
        printf("Test case #%d\n",i++);
        for(int k=2;k<=n;k++)
        {
            if(k%(k-next[k])==0&&k/(k-next[k])!=1)printf("%d %d\n",k,k/(k-next[k]));
        }
        printf("\n");
    }
}