算法竞赛进阶指南---0x15 (KMP) Period

题面

算法竞赛进阶指南---0x15 (KMP) Period_第1张图片
算法竞赛进阶指南---0x15 (KMP) Period_第2张图片

题解

算法竞赛进阶指南---0x15 (KMP) Period_第3张图片

看数据范围,如果使用暴力,双重循环n2 ,字符串长度是1e6 ,肯定会超时,下面讲解正确解法

  1. 首先要知道KMP的 ne[i]=j 以i为终点的后缀和从1开始的前缀最大重合是j(蓝色部分的长度)
  2. 我们可以发现,区间1和区间2,3的字符串是相等的,然后继续划分,使 1 = 4 ,然后 自然 4 = 5 ,5 = 6 ,6 = 7 …一直这样划分,就可以划分出长度为 i -ne[i] 的区间 满足循环
  3. 循环长度已经确定,怎样保证它就是最小的呢(只有区间长度最小,才能划分出更多),如果这个长度不是最小,还可以更小,那么这个子字符串的ne[i]就会相应的增大,就互相矛盾
  4. 我们只需要判断这个循环的长度是否满足条件即可,循环区间肯定大于1个,所以长度肯定小于i,其次就是这个长度必须能被i整除

代码

#include

using namespace std;
const int N = 1e6 + 10;

int n;
char p[N];
int ne[N];

int main() {
     

    int t = 0;
    while (cin >> n && n) {
     
        for (int i = 1; i <= n; i++) cin >> p[i];
        for (int i = 2, j = 0; i <= n; i++) {
     
            while (j && p[i] != p[j + 1]) {
     
                j = ne[j];
            }
            if (p[i] == p[j + 1]) {
     
                j++;
            }
            ne[i] = j;
        }
        cout << "Test case #" << ++t << endl;

        for (int i = 2; i <= n; i++) {
     
            int len=i-ne[i];
            if(len!=i&&i%len==0){
     
                cout<<i<<" "<<i/len<<endl;
            }
        }
        cout << endl;
    }


    return 0;
}

你可能感兴趣的:(#,KMP,算法,KMP)