hdu1358 KMP中next数组的应用

来源:互联网 发布:开淘宝店好做吗 编辑:程序博客网 时间:2024/06/06 06:59

转载自FreeCode#的博客

=>题目传送门<=

题意:将子序列中有周期性前缀的输出并输出其出现的次数

KMP算法。
  这道题考察的是KMP算法中next数组的应用,必须理解透next[]数组代表的含义才能通过它解决这道题。
  思路是先构造出 next[] 数组,下标为 i,定义一个变量 j = i - next[i] 就是next数组下标和下标对应值的差,如果这个差能整除下标 i,即 i%j==0 ,则说明下标i之前的字符串(周期性字符串长度为 i)一定可以由一个前缀周期性的表示出来,这个前缀的长度为刚才求得的那个差,即 j,则这个前缀出现的次数为 i/j 。所以最后输出i和i/j即可。
      举这道题的第二组输入样例为
      其next[]数组为:
    i      0  1  2  3  4  5  6  7  8  9  10 11   a[i]    a  a  b  a  a  b  a  a  b  a  a  b  next[i] -1  0  1  0  1  2  3  4  5  6  7  8 



      next[i]值是0或-1的忽略。

注意:由于输出次数太多 (2 <= N <= 1 000 000),建议用printf输出,否则会超时。

代码:

#include <iostream>#include <stdio.h>using namespace std;char a[1000010];int next[1000010];int n;void GetNext()    //获得a数列的next数组{    int i=0,k=-1;    next[0] = -1;    while(i<n){        if(k==-1){            next[i+1] = 0;            i++;k++;        }        else if(a[i]==a[k]){            next[i+1] = k+1;            i++;k++;        }        else            k = next[k];    }}void DisRes(int num){    int j;    printf("Test case #%d\n",num);    for(int i=0;i<=n;i++){        if(next[i]==-1 || next[i]==0)   //next[i]是-1或0的忽略,说明之前没有周期性前缀            continue;        j = i - next[i];        if(i%j==0)  //能整除,说明存在周期性前缀            printf("%d %d\n",i,i/j);    //输出这个前缀的长度和周期数    }    printf("\n");}int main(){    int num = 0;    while(scanf("%d",&n)!=EOF){        if(n==0) break;        scanf("%s",a);        GetNext();  //获得next[]数组        DisRes(++num);  //输出结果    }    return 0;}