KMP题 hdu3336 hdu3746 hdu 1358 hdu2594


hdu 3336

Count the string

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7242    Accepted Submission(s): 3348


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
 




题意:在算出前缀后暴力的话会TLE,因此考虑用kmp算法,只需要理解next的作用,用dp[i]保存到i为止前缀的数量。

状态转移方程为  dp[i]+=dp[next[i] ]

线性复杂度;

代码:

#include <cstdio>
#include <cstring>

int next[200005];
char s[200005];
inline void calnext(char s[],int next[]) {
    int i,j;
    int len = strlen(s);
    next[0]=-1;
    j=-1;
     for(i=1;i<len;i++) {
        while(j>=0&&s[i]!=s[j+1])
            j=next[j];
        if(s[j+1]==s[i])//上一个循环可能因为 j==-1 而不做,此时不能知道s[i]与s[j+1]的关系。故需要此条件
             j++;
        next[i]=j;
    }
}

int dp[200005];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int slen;
        int i,j;
        memset(next,0,sizeof(next));
        scanf("%d",&slen);
        scanf("%s",s);
        calnext(s,next);
        for(i=0;i<=slen;i++)
            dp[i]=1;
        int ans=0;
        for(i=0;i<slen;i++)
        {
            dp[i]+=dp[next[i]];
            ans+=dp[i];
            ans%=10007;
        }
        printf("%d\n",ans);
    }
    return 0;
}




hdu 3746

Cyclic Nacklace

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5134    Accepted Submission(s): 2321


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


思路  可以通过求  flen= slen-next[slen-1]-1;  来求得循环节

之后只要特判一下 长度整除循环节的情况就行;

不整除就补齐;



代码:


#include <cstdio>
#include <cstring>

int next[100005];
char s[100005];  char t[100005];
inline void calnext(char s[],int next[]) {
    int i,j;
    int len = strlen(s);
    next[0]=-1;
    j=-1;
     for(i=1;i<len;i++) {
        while(j>=0&&s[i]!=s[j+1])
            j=next[j];
        if(s[j+1]==s[i])//上一个循环可能因为 j==-1 而不做,此时不能知道s[i]与s[j+1]的关系。故需要此条件
             j++;
        next[i]=j;
    }
}

int main() {
    int n;
    scanf("%d",&n);
    while(n--) {
        scanf("%s",s); //s代表短串,t代表长串
        int slen=strlen(s);
        calnext(s,next);
        int flen= slen-next[slen-1]-1;  //循环节
        if (flen!=slen&&(slen%flen==0))
        {
            printf("0\n");
            continue;
        }
        int num=slen/flen;
        printf("%d\n",(num+1)*flen-slen);
    }
    return 0;
}


hdu 1358

Period

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5394    Accepted Submission(s): 2601


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 A K , 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



同样是求循环节;


代码:

#include <cstdio>
#include <cstring>

int next[1005000];
char s[1005000];  char t[1005000];
inline void calnext(char s[],int next[]) {
    int i,j;
    int len = strlen(s);
    next[0]=-1;
    j=-1;
     for(i=1;i<len;i++) {
        while(j>=0&&s[i]!=s[j+1])
            j=next[j];
        if(s[j+1]==s[i])//上一个循环可能因为 j==-1 而不做,此时不能知道s[i]与s[j+1]的关系。故需要此条件
             j++;
        next[i]=j;
    }
}

int main() {
    int n;
    int ncase=1;
   while( scanf("%d",&n)!=EOF)
   {
        if(!n)
            return 0;
        scanf("%s",s);
        int slen=strlen(s);
        calnext(s,next);
        printf("Test case #%d\n",ncase++);
        for(int i=2;i<=slen;i++)
        {
            int flen=i-next[i-1]-1;
            if(i%flen==0&&flen!=i)
                printf("%d %d\n",i,i/flen);

        }
        printf("\n");
   }
    return 0;
}



hdu2594

Simpsons’ Hidden Talents

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5340    Accepted Submission(s): 1937


Problem 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
 

可以先把后面的那串字符串接到前面的字符串的后面也可以直接算;
    #include <stdio.h>  
    #include <string.h>  
      
    char str1[50005],str2[50005];  
    int next[50005];  
      
    void get_next(int len2)  
    {  
        int i = 0,j = -1;  
        next[0] = -1;  
        while(i<len2)  
        {  
            if(j == -1 || str2[i] == str2[j])  
            {  
                j++;  
                i++;  
                if(str2[i] == str2[j])  
                    next[i] = next[j];  
                else  
                    next[i] = j;  
            }  
            else  
                j = next[j];  
        }  
    }  
      
      
    int kmp(int len1,int len2)  
    {  
        int i = 0,j = 0;  
        get_next(len2);  
        while(i<len1)  
        {  
            if(j == -1 || str1[i] == str2[j])  
            {  
                i++;  
                j++;  
            }  
            else  
                j = next[j];  
        }  
        return j;  
    }  
      
    int main()  
    {  
        int i,len1,len2,n;  
        while(gets(str2))  
        {  
            gets(str1);  
            len1 = strlen(str1);  
            len2 = strlen(str2);  
            n = kmp(len1,len2);  
            for(i = 0; i<n; i++)  
                putchar(str2[i]);  
            if(n)  
                printf(" ");  
            printf("%d\n",n);  
        }  
      
        return 0;  
    }  

总结:

以前一直觉得kmp的next写的太差了,sunday完爆之。现在才发现写的烂的next才有用=,=
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值