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

 

 

  

 

posted @ 2022-04-25 23:33  syxw  阅读(51)  评论(0)    收藏  举报