题意:有一段序列,若是在第k个之后形成循环节,循环节长度为p,问最小的k + p其中k,p分别是多少?
利用KMP的next数组来求解循环节,因为是从某个数之后形成循环节,所以需要将输入的序列翻转之后,那么每个位置i + 1 - next[i]的值就是当前位置到最后形成的循环节长度,将n - i - 1(位置) + i + 1 - next[i](循环节长度)取最小值即可;
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int N = 1e6 + 5;
int nxt[N];
int a[N];
int main()
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;++i){
int x;
scanf("%d",&x);
a[n - i - 1] = x;
}
memset(nxt,0,sizeof(nxt));
int i = 0,j = 1;
while(j < n){
if(a[i] != a[j] && i != 0){
i = nxt[i - 1];
}else if(a[i] != a[j] && i == 0){
nxt[j] = 0;
j++;
}else if(a[i] == a[j]){
nxt[j] = i + 1;
j++,i++;
}
}
int p,q;
int MIN = inf;
for(int k = 0;k < n;++k){
if(k + 1 - nxt[k] + n - k - 1 < MIN){
MIN = k + 1 - nxt[k] + n - k - 1;
p = n - k - 1;
q = k + 1 - nxt[k];
}
}
printf("%d %d\n",p,q);
return 0;
}