• 2016——3——16 kmp 7题


    1、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2725

      题目大意:找一个串在另一个串中出现的次数

      题解:kmp(纯裸题)

      

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define maxn 1000100
     5 int n,fix,ans,i,lens,lent;
     6 char s[maxn],t[maxn];
     7 int next[maxn];
     8 void getnext()
     9 {
    10     fix=0;
    11     for (i=2; i<=lent; i++)
    12     {
    13         while(fix && t[fix+1]!=t[i]) fix=next[fix]; 
    14         if (t[fix+1]==t[i]) fix++;
    15         next[i]=fix;
    16     }
    17 }
    18 int KMP()
    19 {
    20     int count;
    21     fix=0; count=0;
    22     for (int i=1; i<=lens; i++)
    23     {
    24         while (fix && t[fix+1]!=s[i]) fix=next[fix];
    25         if (t[fix+1]==s[i]) fix++;
    26         if (fix==lent)
    27         {
    28             count++;
    29             fix=next[fix];
    30         }    
    31     }
    32     return count;
    33 }
    34 int main()
    35 {
    36     int z;
    37     scanf("%d",&z);
    38     for (int zz=1; zz<=z; zz++)
    39     {
    40         scanf("%s",t+1);
    41         scanf("%s",s+1);
    42         lens=strlen(s+1); 
    43         lent=strlen(t+1);
    44         memset(next,0,sizeof(next));
    45         getnext();
    46         ans=KMP();
    47         printf("%d
    ",ans);
    48     }
    49     return 0;
    50 }
    View Code

      

    2、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2732

      题目大意:给你一个字符串,让你求出最大重复周期(最大周期不和本身重合)

      题解:kmp或者扩展kmp(但我并未用这种方法),我用的是kmp,但是一直WA,原来是求next数组把while写成了if(手抖毁一生)。

         好吧,写题解了:用kmp求出next数组,然后在去递归next[n],因为j=next[next[n]]一直next下去直到其的next为0就ans+=n-j;

         这就可以求出不和母串一样的最大重复周期,但是这又有一个问题你在求j时要递归时间就有可能为n^2的所以在每次递归时改变next的值就好了(详见代码);

      

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define inf 0x7ffffff
     5 #define maxn 1000100
     6 char s[maxn];
     7 int nnext[maxn];
     8 int n,i,j,fix;
     9 long long ans;
    10 using namespace std;
    11 int main()
    12 {
    13     scanf("%d",&n);
    14     scanf("%s",s+1);
    15     fix=0;
    16     for (int i=2; i<=n; i++)
    17     {
    18         while (fix && s[fix+1]!=s[i]) fix=nnext[fix];
    19         if (s[fix+1]==s[i]) fix++;
    20         nnext[i]=fix;
    21     } 
    22     ans=0;
    23     for (int i=1; i<=n; i++)
    24     {
    25         int j=i;
    26         if (!nnext[j]) continue;
    27         while (nnext[nnext[j]]) nnext[j]=nnext[nnext[j]];
    28         ans+=(i-nnext[j]);
    29     }
    30     printf("%lld
    ",ans);
    31 }
    View Code

    3、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2726

      题目大意:给出一个字母组成的矩阵,找出一个最小的子矩阵,使得这个子矩阵的无限复制扩张之后的矩阵包含原来矩阵如:         

            ABABA 

            ABABA 
            他的最小重复子矩阵是AB 

      题解:还是kmp,只不过要有一点小技巧,就是把一行当作一个元素,那么就有n个元素,然后做kmp找重复子串,那么最小重复子串就为n-next[n],列也做此操作,答案就是

          (n-r[n])*(m-c[m]);

      

     1 #include <cstdio>
     2 #include <cstring>
     3 char s[10005][80], rs[80][10005];
     4 int R[10005], C[10005];
     5 int r, c;
     6 
     7 void get_nextR() 
     8 {  
     9     R[0] = -1;
    10     int j = -1, i = 0;
    11     while(i < r)
    12     {
    13         if(j == -1 || strcmp(s[i], s[j]) == 0)
    14         {
    15             i++;
    16             j++;
    17             R[i] = j;
    18         }
    19         else
    20             j = R[j];
    21     }  
    22 }  
    23 
    24 void get_nextC() 
    25 {  
    26     C[0] = -1;
    27     int j = -1, i = 0;
    28     while(i < c)
    29     {
    30         if(j == -1 || strcmp(rs[i], rs[j]) == 0)
    31         {
    32             i++;
    33             j++;
    34             C[i] = j;
    35         }
    36         else
    37             j = C[j];
    38     }  
    39 } 
    40 
    41 int main()
    42 {
    43     while(scanf("%d %d", &r, &c) != EOF)
    44     {
    45         for(int i = 0; i < r; i++) 
    46             scanf("%s", s[i]);
    47         get_nextR();
    48         for(int i = 0; i < r; i++)
    49             for(int j = 0; j < c; j++)
    50                 rs[j][i] = s[i][j];
    51         get_nextC();
    52         printf("%d
    ", (r - R[r]) * (c - C[c]));
    53     }
    54 }
    View Code

    4、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2724

      题目大意:给定一个字符串,要求找到同时是它前缀也是后缀的字符串的个数,并且输出他们的长度。

      题解:理解一下next数组的用法,从next[n]一直往前求next,那么那些点的坐标就是answer。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define maxn 1000100
     5 int n,ans,fix;
     6 int nnext[maxn];
     7 char s[maxn];
     8 using namespace std;
     9 void show(int n)
    10 {
    11     if (n<=0) return;
    12     show(nnext[n]);
    13     printf("%d ",n);
    14 }
    15 int main()
    16 {
    17     scanf("%d",&n);
    18     scanf("%s",s+1);
    19     fix=0;
    20     for (int i=2; i<=n; i++)
    21     {
    22         while  (fix && s[fix+1]!=s[i]) fix=nnext[fix];
    23         if (s[fix+1]==s[i]) fix++;
    24         nnext[i]=fix;
    25     }
    26     show(n);
    27     return 0;
    28 }
    View Code

    5、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2723

     题目大意:

        现在给一个字符串A,和另一个字符串B。要你每次从B串中从左到右第第一个A串。 
        并且从B串中删除它,直到A串不为B串的子串。问需要几次删除操作。

      题解:next数组的应用,只不过用一个堆记录那些没匹配成功的字符,在用它进行匹配。

     1 #include<cstring>
     2 #include<cstdio>
     3 #include<cstring>
     4 char t[1000100],s[1000100];
     5 int m,n,top,i,fix,ans;
     6 int z[1000100],next[1000010],f[1000010];
     7 using namespace std;
     8 int main()
     9 {
    10     scanf("%s%s",t+1,s+1);
    11     m=strlen(s+1); n=strlen(t+1);
    12     for (fix=0,i=2; i<=n; i++)
    13     {
    14         while (fix && t[fix+1]!=t[i]) fix=next[fix];
    15         if (t[fix+1]==t[i]) fix++;
    16         next[i]=fix;
    17     }
    18     for (int i=1; i<=m; i++)
    19     {
    20         fix=f[z[top]];
    21         while (fix && t[fix+1]!=s[i]) fix=next[fix];
    22         if (t[fix+1]==s[i]) fix++;
    23          
    24         if (fix==n) top-=(n-1),ans++;
    25             else
    26         f[i]=fix, z[++top]=i;
    27     } 
    28     printf("%d
    ",ans);
    29 }
    View Code

    6、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2719

      题目大意:给出一个串S,它包含 N 个字符。设 Pi = S [ 1 .. I ] ,对于一些 Pi , 如果Pi能表示成K个字符串相连而成的(K > 1 ,且K尽量大),则打印I和K。

      题解:如果i mod(i-next[i]) =0 && (i/(i-next[i])>1 输出答案(i);

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define inf 0x7fffffff
     5 int n,ans;
     6 int nnext[1000100];
     7 char s[1000100];
     8 using namespace std;
     9 int main()
    10 {
    11     int z=0;
    12     while (true)
    13     {
    14         scanf("%d",&n);
    15         if (n==0) break;
    16         z++;
    17         printf("Test case #%d
    ",z);
    18         scanf("%s",s+1);
    19         ans=0;
    20         int fix=0;
    21         for (int i=2; i<=n; i++)
    22         {
    23             while (fix && s[fix+1]!=s[i]) fix=nnext[fix];
    24             if (s[fix+1]==s[i]) fix++;
    25             nnext[i]=fix;
    26         }
    27         for (int i=2; i<=n; i++)
    28         {
    29             int k=i-nnext[i];
    30             if (i % k==0 && i/k>1) printf("%d %d
    ",i,i/k);
    31         }
    32         printf("
    ");
    33     }
    34 }
    View Code

    7、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2720

      题目大意:给你一个字符串,它是由某个字符串不断自我连接形成的。 但是这个字符串是不确定的,现在只想知道它的最短长度是多少.

      题解:同上;

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define inf 0x7fffffff
     5 int n,ans;
     6 int nnext[1000100];
     7 char s[1000100];
     8 using namespace std;
     9 int main()
    10 {
    11     scanf("%d",&n);
    12     scanf("%s",s+1);
    13     ans=0;
    14     int fix=0;
    15     for (int i=2; i<=n; i++)
    16     {
    17         while (fix && s[fix+1]!=s[i]) fix=nnext[fix];
    18         if (s[fix+1]==s[i]) fix++;
    19         nnext[i]=fix;
    20     }
    21     printf("%d
    ",n-nnext[n]);
    22 }
    View Code
    我太蒟蒻了,所以神犇们留下意见让我跪膜
  • 相关阅读:
    Flink SQL Client初探
    ansible快速部署cassandra3集群
    利用TfidfVectorizer进行中文文本分类(数据集是复旦中文语料)
    spark读取HDFS目录时报错Failed on local exception: com.google.protobuf.InvalidProtocolBufferException
    Spark学习进度-Spark环境搭建&Spark shell
    jquery获取select选中的值
    java零基础到架构师学习线路(附视频教程)
    plsql连接远程oracle数据库
    如何在通用异常处理时获取到方法名称(获取注解参数JoinPoint)
    java:找不到符号(使用lombok)
  • 原文地址:https://www.cnblogs.com/HQHQ/p/5285438.html
Copyright © 2020-2023  润新知