KMP[入门newing

1)Period
Problem Description
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.

Input
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.

Output
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.

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4
from :https://www.cnblogs.com/yym2013/p/3586495.html
 KMP算法。
 == 这道题考察的是KMP算法中next数组的应用==,必须理解透next[]数组代表的含义才能通过它解决这道题。
  思路是先构造出 next[] 数组,下标为 i,定义一个变量 j = i - next[i] 就是next数组下标和下标对应值的差,如果这个差能整除下标 i,即 i%j==0 ,则说明下标i之前的字符串(周期性字符串长度为 i)一定可以由一个前缀周期性的表示出来,这个前缀的长度为刚才求得的那个差,即 j,则这个前缀出现的次数为 i/j 。所以最后输出i和i/j即可。

#include <iostream>
#include<cstdio>
using namespace std;
int lenp;
const int N=1000010;
int nt[N];
char p[N];
void getnext()
{
    int j=-1,i=0;
    nt[0]=-1;
    while(i<lenp)
    {
        if(j==-1||p[i]==p[j])
        {
            i++;
            j++;
            nt[i]=j;
        }else
        {
            j=nt[j];
        }
    }
}
int main()
{
    int tt=0;
   while(cin>>lenp)
   {
       if(lenp==0) return 0;
       printf("Test case #%d\n",++tt);
      scanf("%s",p);
       getnext();
       for(int i=0;i<=lenp;i++)
       {
           if(nt[i]>0&&i%(i-nt[i])==0)
           {
               printf("%d %d\n",i,i/(i-nt[i]));//前缀长度,周期
           }
       }
       puts("");
   }
    return 0;
}

在这里插入图片描述2)
Number Sequence
Time Limit : 10000/5000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 52 Accepted Submission(s) : 32
Problem Description
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

Source
HDU 2007-Spring Programming Contest
题目大意:给你两个数组的所有元素,让你对它们进行匹配,当位置为多少时候它们能完全匹配
板子

#include <iostream>
#include<cstdio>
using namespace std;
int lenp,lent;
const int N=1000010,M=10010;
int p[M],t[N],nt[M];
void getnext()
{
    nt[0]=-1;
    int k=-1;
    int j=0;
    while(j<lenp)
    {
        if(k==-1||p[j]==p[k])
        {
            ++k;
            ++j;
            if(p[j]!=p[k])
            {
                nt[j]=k;
            }else nt[j]=nt[k];
        }else
        {
            k=nt[k];
        }
    }

}
int kmp()
{
    int i=0,j=0;
    while(i<lent&&j<lenp)
    {
        if(j==-1||p[j]==t[i])
        {
            i++;
            j++;
        }else
        {
            j=nt[j];
        }

    }
    if(j==lenp ) return i-j+1;
    else return -1;
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--){
        scanf("%d%d",&lent,&lenp);
        for(int i=0;i<lent;i++)
        {
            scanf("%d",&t[i]);
        }
        for(int i=0;i<lenp;i++)
        {
            scanf("%d",&p[i]);
        }
        getnext();
        printf("%d\n",kmp());
    }
    return 0;
}

Substrings
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 38 Accepted Submission(s) : 29
Problem Description
You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

Input
The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

Output
There should be one line per test case containing the length of the largest string found.

Sample Input

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output

2
2

1.kmp
2.暴力枚举(reverse 的头文件是algorithm)

#include <iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000;
int nt[N];
void getnext( string p)
{
    int lenp=p.size();
    memset(nt,0,sizeof(nt));
    nt[0]=-1;
    int k=-1;
    int j=0;
    while(j<lenp)
    {
        if(k==-1||p[j]==p[k])
        {
            ++k;
            ++j;
            if(p[j]!=p[k])
            {
                nt[j]=k;
            }else nt[j]=nt[k];
        }else
        {
            k=nt[k];
        }
    }

}
bool kmp(string p,string t)
{
    getnext(p);
    int lent=t.size(),lenp=p.size();
    int i=0,j=0;
    while(i<lent)
    {
        if(j==-1||p[j]==t[i])
        {
            i++;
            j++;
        }else
        {
            j=nt[j];
        }
   if(j>=lenp ) return true;
    }

    return false ;
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--){
            int m;
        scanf("%d",&m);
    string str[110];
        for(int i=0;i<m;i++)
        {
            cin>>str[i];
        }
        string w,k,ans;
        int l=str[0].size();
        for(int i=0;i<l;i++)
        {
            for(int j=i;j<l;j++)
            {
                w=str[0].substr(i,j-i+1);
                k=w;
                reverse(k.begin(),k.end());
                int f=1;
                for(int ff=1;ff<m;ff++)
                {
                    if(!kmp(w,str[ff])&&!kmp(k,str[ff]))
                      {
                          f=0;
                          break;
                      }
                }
                if(f&&w.size()>ans.size())
                {
                    ans=w;
                }

            }
        }
        printf("%d\n",ans.size());

    }
    return 0;
}

补充:C语言strstr的用法

#include<stdio.h>
#include<string.h>
using namespace std;
char str[110][110];
char w[110],f[110];
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        int m;
        scanf("%d ",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%s",str[i]);
        }
        int l=strlen(str[0]),ans=0;
        for(int i=0;i<l;i++)
        {
            for(int j=i;j<l;j++)
            {
                int h=0;
                memset(w,0,sizeof(w));
                memset(f,0,sizeof(f));
                for(int k=i;k<=j;k++)
                {
                    w[h]=str[0][k];
                    f[j-i-h]=str[0][k];
                    h++;
                }
                int fff=1;
                for(int dd=1;dd<m;dd++)
                {
                    if(!strstr(str[dd],w)&&!(strstr(str[dd],f)))
                    {
                        fff=0;
                        break;

                    }
                }
                if(fff&&ans<j-i+1)
                {
                    ans=j-i+1;
                }
            }
        }
        printf("%d\n",ans);
    }
}

亲和串
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 19496 Accepted Submission(s): 8572

Problem Description
人随着岁数的增长是越大越聪明还是越大越笨,这是一个值得全世界科学家思考的问题,同样的问题Eddy也一直在思考,因为他在很小的时候就知道亲和串如何判断了,但是发现,现在长大了却不知道怎么去判断亲和串了,于是他只好又再一次来请教聪明且乐于助人的你来解决这个问题。
亲和串的定义是这样的:给定两个字符串s1和s2,如果能通过s1循环移位,使s2包含在s1中,那么我们就说s2 是s1的亲和串。

Input
本题有多组测试数据,每组数据的第一行包含输入字符串s1,第二行包含输入字符串s2,s1与s2的长度均小于100000。

Output
如果s2是s1的亲和串,则输出"yes",反之,输出"no"。每组测试的输出占一行。

Sample Input

AABCD
CDAA
ASD
ASDF

Sample Output

yes
no

Author
Eddy

c中strstr的使用

#include<string.h>
#include<stdio.h>
using namespace std;
char s1[100010],s2[100010],c[200010];
int main()
{
    while(scanf("%s",s1)!=EOF)
    {
        scanf("%s",s2);
        strcpy(c,s1);
        strcat(c,s1);
        if(strstr(c,s2)!=NULL) printf("yes\n");
        else printf("no\n");
    }

}

kmp

#include <iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
const int N=100010;
int nt[N];
char str1[N],t[2*N],p[N];
void getnext( )
{
    int lenp=strlen(p);
    memset(nt,0,sizeof(nt));
    nt[0]=-1;
    int k=-1;
    int j=0;
    while(j<lenp)
    {
        if(k==-1||p[j]==p[k])
        {
            ++k;
            ++j;
            if(p[j]!=p[k])
            {
                nt[j]=k;
            }else nt[j]=nt[k];
        }else
        {
            k=nt[k];
        }
    }

}
bool kmp()
{
    getnext();
    int lent=strlen(t),lenp=strlen(p);
    int i=0,j=0;
    while(i<lent)
    {
        if(j==-1||p[j]==t[i])
        {
            i++;
            j++;
        }else
        {
            j=nt[j];
        }
   if(j>=lenp ) return true;
    }

    return false ;
}
int main()
{
    while(scanf("%s",str1)!=EOF)
    {
        scanf("%s",p);
        strcpy(t,str1);
        strcat(t,str1);
        if(kmp()) cout<<"yes"<<endl;
        else cout<<"no"<<endl;
    }
    return 0;
}

Count the string
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 39 Accepted Submission(s) : 28
Problem Description
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

Author
foreverlin@HNU

Source
HDOJ Monthly Contest – 2010.03.06

#include <iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
const int N=200010;
int nt[N];
char p[N];
void getnext( )
{
    int lenp=strlen(p);
    memset(nt,0,sizeof(nt));
    nt[0]=-1;
    int k=-1;
    int j=0;
    while(j<lenp)
    {
        if(k==-1||p[j]==p[k])
        {
            ++k;
            ++j;
            nt[j]=k;
        }else
        {
            k=nt[k];
        }    }

}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        int n,ans=0;
        scanf("%d",&n);
        scanf("%s",p);
        getnext();
        for(int i=1;i<=n;i++)
        {
            int p=nt[i];
            while(p!=-1)
            {
                p=nt[p];
                ans++;ans%=10007;
            }

        }
        printf("%d\n",ans);
    }
    return 0;
}

'a _b_c_a_b_c <-p[]
‘-1’ 0 0 _0_1 _2 3 <-nt[]
1.nt[i] == -1表示它没有前缀
2.举例 :
nt[4]=1,说明前面有一个同样的前缀其长度是1(也就是‘a’),这说明至少该子串中有2个a,所以进行 /加一 /操作。然后跳到 nt[1],nt[1]==0,说明该字符串的最长前缀长度为0,但是由于是从后面跳过来的,这个‘a’也未经过处理所以+1,接着nt[i]为-1,//结束

Best Reward
Best Reward
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4828 Accepted Submission(s): 1985

Problem Description
After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit.

One of these treasures is a necklace made up of 26 different kinds of gemstones, and the length of the necklace is n. (That is to say: n gemstones are stringed together to constitute this necklace, and each of these gemstones belongs to only one of the 26 kinds.)

In accordance with the classical view, a necklace is valuable if and only if it is a palindrome - the necklace looks the same in either direction. However, the necklace we mentioned above may not a palindrome at the beginning. So the head of state decide to cut the necklace into two part, and then give both of them to General Li.

All gemstones of the same kind has the same value (may be positive or negative because of their quality - some kinds are beautiful while some others may looks just like normal stones). A necklace that is palindrom has value equal to the sum of its gemstones’ value. while a necklace that is not palindrom has value zero.

Now the problem is: how to cut the given necklace so that the sum of the two necklaces’s value is greatest. Output this value.

Input
The first line of input is a single integer T (1 ≤ T ≤ 10) - the number of test cases. The description of these test cases follows.

For each test case, the first line is 26 integers: v1, v2, …, v26 (-100 ≤ vi ≤ 100, 1 ≤ i ≤ 26), represent the value of gemstones of each kind.

The second line of each test case is a string made up of charactor ‘a’ to ‘z’. representing the necklace. Different charactor representing different kinds of gemstones, and the value of ‘a’ is v1, the value of ‘b’ is v2, …, and so on. The length of the string is no more than 500000.

Output
Output a single Integer: the maximum value General Li can get from the necklace.

Sample Input

2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
aba
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
acacac

Sample Output

1
6

Source
2010 ACM-ICPC Multi-University Training Contest(18)——Host by TJU

可以考虑马拉车的写法~~

#include<string>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<vector>
using namespace std;
const int N=500010;
int LL[N],RR[N],sum[N];
char s[N];
int mp[27];
void  Manacher()
{
    string t="$#";
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        t+=s[i];
        t+='#';
    }
    vector<int>p(t.size(),0);
    int mx=0,id=0,reslen=0,rescenter=0;
    for(int i=1;i<t.size();++i)
    {
        p[i]=mx>i?min(p[2*id-i],mx-i):1;
        while(t[i-p[i]]==t[i+p[i]]) ++p[i];
        if(mx<i+p[i])
        {
            mx=i+p[i];
            id=i;
        }
        if(reslen<p[i])
        {
            reslen=p[i];
            rescenter=i;
        }
        if(i==p[i]) LL[i-1]=1;
        if(t.size()==i+p[i]) RR[p[i]-1]=1;
    }

}
int main()
{
  int tt;
  scanf("%d",&tt);
  while(tt--)
  {
      for(int i=0;i<27;i++)
      {
          scanf("%d",&mp[i]);
      }
      scanf("%s",s);
      memset(sum,0,sizeof(sum));
      memset(LL,0,sizeof(LL));
      memset(RR,0,sizeof(RR));
      sum[0]=mp[s[0]-'a'];
      int len=strlen(s);
      for(int i=1;i<len;i++)
      {
          sum[i]=sum[i-1]+mp[s[i]-'a'];
      }
      Manacher();
      int ans=0;
      for(int i=1;i<len;i++)
      {
          int res=0;
          if(LL[i]) res+=sum[i-1];
          if(RR[len-i]) res+=sum[len-1]-sum[i-1];
          ans=max(ans,res);
      }
      printf("%d\n",ans);
  }
}

Cyclic Nacklace
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 29 Accepted Submission(s) : 23
Problem Description
CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of “HDU CakeMan”, he wants to sell some little things to make money. Of course, this is not an easy task.

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl’s fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls’ lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet’s cycle is 9 and its cyclic count is 2:

Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.

Input
The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases. Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by ‘a’ ~‘z’ characters. The length of the string Len: ( 3 <= Len <= 100000 ).

Output
For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.

Sample Input

3
aaa
abca
abcde

Sample Output

0
2
5

Author
possessor WC

Source
HDU 3rd “Vegetable-Birds Cup” Programming Open Contest
考察nt[]数组;

#include <iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
int lenp;
const int N=100010;
int nt[N];
char p[N];
void getnext()
{
    int j=-1,i=0;
    nt[0]=-1;
    while(i<lenp)
    {
        if(j==-1||p[i]==p[j])
        {
            i++;
            j++;
            nt[i]=j;
        }else
        {
            j=nt[j];
        }
    }
}
int main()
{
   int tt;
   scanf("%d",&tt);
   while(tt--)
   {
       scanf("%s",p);
       lenp=strlen(p);
       getnext();
       if(nt[lenp]==0)
       {
           printf("%d\n",lenp);
       }else
       {
           int t=lenp-nt[lenp];
           if(lenp%t==0) printf("0\n");
           else printf("%d\n",t-lenp%t);
       }
   }
   }



Clairewd’s message
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 26 Accepted Submission(s) : 19
Problem Description
Clairewd is a member of FBI. After several years concealing in BUPT, she intercepted some important messages and she was preparing for sending it to ykwd. They had agreed that each letter of these messages would be transfered to another one according to a conversion table.
Unfortunately, GFW(someone’s name, not what you just think about) has detected their action. He also got their conversion table by some unknown methods before. Clairewd was so clever and vigilant that when she realized that somebody was monitoring their action, she just stopped transmitting messages.
But GFW knows that Clairewd would always firstly send the ciphertext and then plaintext(Note that they won’t overlap each other). But he doesn’t know how to separate the text because he has no idea about the whole message. However, he thinks that recovering the shortest possible text is not a hard task for you.
Now GFW will give you the intercepted text and the conversion table. You should help him work out this problem.

Input
The first line contains only one integer T, which is the number of test cases. Each test case contains two lines. The first line of each test case is the conversion table S. S[i] is the ith latin letter’s cryptographic letter. The second line is the intercepted text which has n letters that you should recover. It is possible that the text is complete. [hint]Range of test data: T<= 100 ; n<= 100000; [/hint]

Output
For each test case, output one line contains the shorest possible complete text.

Sample Input

2
abcdefghijklmnopqrstuvwxyz
abcdab
qwertyuiopasdfghjklzxcvbnm
qwertabcde

Sample Output

abcdabcd
qwertabcde

Author
BUPT

Source
2012 Multi-University Training Contest 1
translation:给两个串第一个串是翻译表(密文可以通过翻译表翻译成明文),第二个串是由密文+明文组成,前面是密文(完整的),后面是明文(未必完整)

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<string.h>
using namespace std;
int lenp;
const int N=100010;
char p[N];
int nt[N];
map<char ,char>mp;
void getnext()
{
    nt[0]=-1;
    int k=-1;
    int j=0;
    while(j<lenp)
    {
        if(k==-1||p[j]==mp[p[k]])
        {
            ++k;
            ++j;
            if(p[j]!=mp[p[k]])
            {
                nt[j]=k;
            }else nt[j]=nt[k];
        }else
        {
            k=nt[k];
        }
    }

}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--){
        mp.clear();
        getchar();
        char s;
        for(int i=0;i<27;i++)
        {
            s=getchar();
            mp[s]='a'+i;
        }
        scanf("%s",p);
        lenp=strlen(p);
        getnext();
        int ans=lenp-nt[lenp];
        if(nt[lenp]>(lenp+1)/2)
        {
            ans=(lenp+1)/2;
        }
        for(int i=0;i<ans;i++)
        {
            printf("%c",p[i]);
        }
        for(int i=0;i<ans;i++)
        {
            printf("%c",mp[p[i]]);
        }
        puts("");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值