poj1961

先kmp匹配一遍

设s的下标为1~n
则当 i % ( 1 − n x t i ) = 0 i\%(1-nxt_i)=0 i%(1nxti)=0时有 K = 1 − n x t i K=1-nxt_i K=1nxti的的答案

证明:
s l , r s_{l,r} sl,r表示由第 l l l位到第 r r r位组成的字符串(inclusive)
l e n = i − n x t i len=i-nxt_i len=inxti
n x t nxt nxt的定义可知
s 1 , i − l e n = s l e n + 1 , i s_{1,i-len}=s_{len+1,i} s1,ilen=slen+1,i
由于 i % l e n = 0 i\%len=0 i%len=0
所以可以将 s 1 , i − l e n s_{1,i-len} s1,ilen s l e n + 1 , i s_{len+1,i} slen+1,i分别拆分为 i l e n − 1 \frac{i}{len}-1 leni1个字符串,且分别相当
所以在 s 1 , i s_{1,i} s1,i中每组 l e n len len长度的字符串相等,满足题意

并且这样一定是最优的(自行证明)

值得指出的一个性质是,一个字符串的任意循环元长度必然是最小循环元长度的倍数,证明留作读者思考。——《算法竞赛进阶指南》

对。试着说明:
在kmp匹配nxt数组时,我们是有“备选”选项的

while(j&&s[i-1]!=s[j+1-1])j=nxt[j];

若一个循环元的长度为l,则i-l必然为nxt_i的“备选”选项
nxt_i的备选选项有nxt_(nxt_i)等,写得清楚点形如 n x t n x t i , n x t n x t n x t i nxt_{nxt_i},nxt_{nxt_{nxt_i}} nxtnxti,nxtnxtnxti
若其中有某个位置上的循环元长度不为len
则表示可以把a个长度为len的写成len个长度为a的(a,len互质)
这len个长度为a的串的第一个字符为s_a,s_2a%len,s_3a%len…s_len*a%len, 因为a,len互质,其实就是s_1,s_2,…s_len(并不一一对应)
这样就说明:长度为len的这个循环元每一位都相等!那么它一定可以再分,矛盾。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
char s[1000005];
int nxt[1000005];
int main()
{
	int tot=0;
	while(scanf("%d",&n)&&n)
	{
		scanf("%s",s);
		printf("Test case #%d\n",++tot);
		int n=strlen(s);
		nxt[1]=0;
		for(int i=2,j=0;i<=n;++i)
		{
			while(j&&s[i-1]!=s[j+1-1])j=nxt[j];
			if(s[i-1]==s[j+1-1])++j;
			nxt[i]=j;
		}
		for(int i=1;i<=n;++i)
		{
			if(nxt[i]&&i%(i-nxt[i])==0)printf("%d %d\n",i,i/(i-nxt[i]));
		}
		printf("\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值