P3435 [POI2006] OKR-Periods of Words
网址:https://www.luogu.com.cn/problem/P3435
题目的要求是:
1.输入一个字符串a
2.找到一个a的前缀p——p的条件需满足 ① p为a的前缀
② p≠a
3.用字符串Q表示a的周期 <==> Q为a的p前缀,同时a为 Q+Q 的前缀
4.所求为 a 的所有前缀的最大周期之和
也就是说 对于给定的字符串 a ,我们需要先确定其每一个前缀p[i]。
求出其中最长的,使得 p[i] + p[i] 能够被原来的字符串 a 覆盖。
最后求出所有的、这些能满足的长度和。
对于每个前缀i,令j=i,然后在j>0的情况下令j=next[j],最小的j就是答案,此时ans+=i-j
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
char a[1000010];
int n,fail[1000010];//先定义两个用于储存的组
int main(){
scanf("%d",&n);//先输入字符串a的长度
scanf("%s",a);//字符串a的输入
int i,j;
ll ans=0;//这个ll就是前面定义的#define ll long long
fail[0]=fail[1]=0;//初始化fail的第一第二个元素为0
j=0;
for(i=1;i<n;i++){//第一个循环,从1到n,遍历
while(j&&(a[i]!=a[j])) {//这里就是通过j以及以及a[i]与a[j]来判断
j=fail[j];//将fail[j]的值赋予j
}
j+=(a[i]==a[j]);//这里是当 a[i] 与 a[j] 的值相等时,j++
fail[i+1]=j;//将j的值保存在后一个fail里
}
for(i=1;i<=n;i++){
j=i;
while(fail[j]) {//用while循环来获取可能的j值
j=fail[j];
}//这个循环通过fail[j]的值来获取,当fail[j]≠0时继续,直到获取到使得fail[j]=0的前一个j值
if(fail[i]!=0) {
fail[i]=j;
}//当fail[i]≠0时,令fail[i]=j
ans+=i-j;//ans=ans+i-j
}
printf("%lld",ans);
}
参考代码地址:https://www.luogu.com.cn/blog/dedicatus545/solution-p3435

浙公网安备 33010602011771号