2016——3——16 kmp 7题

来源:互联网 发布:拟线性偏好知乎 编辑:程序博客网 时间:2024/05/01 20:01
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\n",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\n",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         else20             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         else37             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\n", (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             else26         f[i]=fix, z[++top]=i;27     } 28     printf("%d\n",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\n",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\n",i,i/k);31         }32         printf("\n");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",n-nnext[n]);22 }
View Code

 

0 0
原创粉丝点击