KMP题目

A - Sum Problem
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

Homer: Marge, I just figured out a way to discover some of the talents we weren’t aware we had. 
Marge: Yeah, what is it? 
Homer: Take me for example. I want to find out if I have a talent in politics, OK? 
Marge: OK. 
Homer: So I take some politician’s name, say Clinton, and try to find the length of the longest prefix 
in Clinton’s name that is a suffix in my name. That’s how close I am to being a politician like Clinton 
Marge: Why on earth choose the longest prefix that is a suffix??? 
Homer: Well, our talents are deeply hidden within ourselves, Marge. 
Marge: So how close are you? 
Homer: 0! 
Marge: I’m not surprised. 
Homer: But you know, you must have some real math talent hidden deep in you. 
Marge: How come? 
Homer: Riemann and Marjorie gives 3!!! 
Marge: Who the heck is Riemann? 
Homer: Never mind. 
Write a program that, when given strings s1 and s2, finds the longest prefix of s1 that is a suffix of s2.

Input

Input consists of two lines. The first line contains s1 and the second line contains s2. You may assume all letters are in lowercase.

Output

Output consists of a single line that contains the longest string that is a prefix of s1 and a suffix of s2, followed by the length of that prefix. If the longest such string is the empty string, then the output should be 0. 
The lengths of s1 and s2 will be at most 50000.

Sample Input

clinton
homer
riemann
marjorie

Sample Output

0
rie 3


对话都是废话,只看最后一句when given strings s1 and s2, finds the longest prefix of s1 that is a suffix of s2.马上就想到把s2接到s1后面成为一个新的字符串,然后找next[n]就完了,我看到很多博客还去找s1前缀和找s2的后缀,然后来匹配,感觉好麻烦。是我太机智(但是并没有觉得想到这个方法很巧妙)还是他们太死板?

代码:

#include<stdio.h>
#include<string.h>

#define MaxSize 500005
#define inf 0x3f3f3f3f
#define LL long long int

char s[2*MaxSize],s2[MaxSize];
int next[2*MaxSize];
int n;

void get_next()
{
  int i=0;
  int j=next[0]=-1;

  while(i<n)
    {
      if(j==-1 || s[j]==s[i])
        next[++i]=++j;

      else j=next[j];
    }
}

int main()
{
  while(~scanf("%s%s",s,s2))
    {
      int len=strlen(s);

      s[len]='A';
      s[len+1]='\0';
      /*为了防止接在一起之后出现一种神奇的情况,中间必须加上一个字符隔开。比如s1:abca,s2:bcab,
      正确答案应该是ab。但如果直接接到一起变成了abcabcab,相同前后缀就变成了abcab,这样前缀都超过s1的长度明显就不行了。
      所以中间应加一个字母隔开防止越界(题上说了给的s1和s2只有小写字母,于是我们就用大写字母隔),
      变成abcaAbcab,这样就绝对不会出现前后缀越界的情况了*/

      strcat(s,s2);

      n=strlen(s);

      get_next();

      s[next[n]]='\0';//用for输出%c多半会超时,这里手动加个结束符,给出地址用%s输出速度会快很多

      printf("%s",s);

      if(next[n]!=0) printf(" ");

      printf("%d\n",next[n]);
    }

  return 0;
}








C - 亲和串
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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


思路:

既然可以循环匹配,就把原串首尾连接。比如原串是abcd,我们就abcd+abc变成abcdabc,这样循环问题就解决了。但是如果目标串是bcdab,这样在连接后的新串里面是找得到的,感觉是合法的。但是在原串中循环匹配的时候这是不合法的,因为出现了后面又走到了b,已经开始重叠了。解决这个问题很简单,判断如果目标串长度大于原串,就一定找不到。要能在原串中循环匹配成功,长度必定是小于等于原串长度的。


代码;

#include<stdio.h>
#include<string.h>

#define MaxSize 100005
#define inf 0x3f3f3f3f
#define LL long long int

char s[MaxSize],s1[2*MaxSize],s2[MaxSize];
int next[MaxSize];
int n,m;

void get_next()
{
  int i=0;
  int j=next[0]=-1;

  while(i<m)
    {
      if(j==-1 || s2[i] == s2[j])
        next[++i]=++j;

      else
        j=next[j];
    }
}

void find()
{
  int i=0;
  int j=0;

  while(i<n)
    {
      if(j==-1 || s1[i]==s2[j])
        {
          i++;
          j++;
        }

      else
        j=next[j];

      if(j==m)
        {
          printf("yes\n");
          return;
        }
    }

  printf("no\n");
}

int main()
{
  while(~scanf("%s%s",s,s2))
    {
      strcpy(s1,s);
      strcat(s1,s);

      n=strlen(s1)-1;
      s1[n]='\0';

      m=strlen(s2);

      if(m > strlen(s))
      {
          printf("no\n");
          continue;
      }

      get_next();

      find();
    }

  return 0;
}



F - Seek the Name, Seek the Fame
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm: 

Step1. Connect the father's name and the mother's name, to a new string S. 
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S). 

Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:) 

Input

The input contains a number of test cases. Each test case occupies a single line that contains the string S described above. 

Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000. 

Output

For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.

Sample Input

ababcababababcabab
aaaaa

Sample Output

2 4 9 18
1 2 3 4 5

思路:

这道题就是把所有的相同前后缀长度输出来,就是把原来的只求最大next[n]变成了 求长度从0~next[n]的相同前后缀。于是在next[]求到最后一步的时候,对j=next[j]不断进行迭代就行了。


代码:

#include <stdio.h>
#include <string.h>
#include <stack>
#include <iostream>
using namespace std;

#define MaxSize 400005

int n;
int next[MaxSize];
char s[MaxSize];

void get_next()
{
  int i=0;
  int j=next[0]=-1;
  stack<int>sta;

  while(i<n)
    {
      if(j==-1 || s[i]==s[j])
        {
            next[++i] = ++j;

            if(i==n)
            {
                i--;
                j--;

                while(j!=-1)
                {
                    if(s[i]==s[j])
                    sta.push(j+1);

                    j=next[j];
                }

                while(!sta.empty())
                {
                    printf("%d ",sta.top());
                    sta.pop();
                }

                printf("%d\n",n);

                break;
            }
        }

      else
        j=next[j];
    }
}

int main()
{
  while(~scanf("%s",s))
    {
      n=strlen(s);

      get_next();
    }
  return 0;
}









E - Power Strings
Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

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

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




遇到‘.’就停止,傻狍子出题人咋不写出来,还以为是不小心多打的句号,坑的一笔。这道题就是求字符串由多少个相同的最小cell组成,这个代码的思路我想到过,但是不知道是不是真的可行,都准备放弃了,结果看了别人的博客真的可以这样。


代码:

#include <stdio.h>
#include <string.h>
#include <stack>
#include <iostream>
using namespace std;

#define MaxSize 1000005

char s[MaxSize];
short next[MaxSize];
int n;

void get_next()
{
  int i=0;
  int j=next[0]=-1;

  while(i<n)
    {
      if(j==-1 || s[i]==s[j])
        next[++i]=++j;

      else
        j=next[j];
    }

  //int len = n-next[n];//告诉你们一件可怕的事,这样写的要wa的。明明是和下面那句等价的,但是它就要wa,就是不知道为什么,真可怕。
  int len = i-j;


  if(n%len == 0)
    printf("%d\n",n/len);

  else
    printf("1\n");
}

int main()
{
  while(~scanf("%s",s) && strcmp(s,".")!=0)
    {
      n=strlen(s);

      get_next();
    }

  return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章