码迷,mamicode.com
首页 > 其他好文 > 详细

POJ2406 Power Strings POJ1961 Period

时间:2020-07-17 13:49:40      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:turn   本质   http   math   scanf   循环   fail   表示   test   

http://poj.org/problem?id=2406
http://poj.org/problem?id=1961
几乎是一个题

1961是对于第 \(i\) 位,求 \([1,i]\) 能不能由一段字符循环一次以上组成,输出 \(i\) 和这样的长度最小的循环节循环次数
2406是只对第 \(n\) 位输出最小长度循环节循环次数


kmp,考虑 kmp 的 \(fail\) 数组,\(fail_i\) 表示的是如果 \(i\) 失配,那么要从哪一位开始继续匹配
更本质的,他是 \([1,i]\) 中,最长的前缀等于后缀的长度
例如 \(fail_i=m\),那么字串 \([1,m]=[i-m+1,i]\),如果这两个区间的并集等于整个区间,那么 \(i-fail_i\)可能 是这个区间的循环节长度
因为并集等于整个区间,所以 \(\forall 1\le j \le fail_i,s(j)=s(j+i-fail_i)\)
对于这个式子也可以理解为前缀向后移动了 \(i-fail_i\) 位得到了后缀,所以相当于每一个区间内字符都与向后移动 \(i-fail_i\) 位的字符相同

因此,只要 \(i \bmod i-fail_i=0\),就说明了 \(i-fail_i\)\([1,i]\) 最小循环节长度(这也是为什么刚才说可能)

POJ2406

char s[6000005];
int fail[6000005];
int main(){
	scanf("%s",s+1);
	while(s[1]!=‘.‘){
		int n=std::strlen(s+1);
		fail[1]=0;
		for(reg int j,i=2;i<=n;i++){
			j=fail[i-1];
			while(j&&s[j+1]!=s[i]) j=fail[j];
			if(j) fail[i]=j+1;
			else fail[i]=(s[1]==s[i]);
		}
		printf("%d\n",(n%(n-fail[n]))?1:(n/(n-fail[n])));
		scanf("%s",s+1);
	}
	return 0;
}

POJ1961

char s[6000005];
int fail[6000005];
int n;
int main(){
	scanf("%d",&n);
	int T=0;
	while(n){
		scanf("%s",s+1);
		fail[1]=0;
		for(reg int j,i=2;i<=n;i++){
			j=fail[i-1];
			while(j&&s[j+1]!=s[i]) j=fail[j];
			if(j) fail[i]=j+1;
			else fail[i]=(s[1]==s[i]);
		}
		printf("Test case #%d\n",++T);
		for(reg int i=2;i<=n;i++)
			if(!(i%(i-fail[i]))&&i/(i-fail[i])>1) printf("%d %d\n",i,i/(i-fail[i]));
		EN;
		scanf("%d",&n);
	}
	return 0;
}

POJ2406 Power Strings POJ1961 Period

标签:turn   本质   http   math   scanf   循环   fail   表示   test   

原文地址:https://www.cnblogs.com/suxxsfe/p/13329179.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!