【题解】UVA-11452 Dancing the Cheeky-Cheeky 利用kmp求候选border

本文探讨了在给定由1,2,3,4字符组成的字符串s的情况下,如何通过字符串t(作为3s的真前缀且长度大于等于|2s|)找到其后8个字符的方法。关键在于使用前缀函数检查|s|和|t|的关系,验证前2|s|个字符的周期性,并确保t的剩余后缀为合法候选。通过KMP算法的扩展应用,实现对候选border的有效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有一个由字符1,2,3,4组成的字符串s。给定一个字符串t,t一定是3s的一个长度大于等于|2s|的真前缀,求t后面的8个字符。


枚举s的长度,如果2|s|<=|t|<3|s|,并且第0个后缀和第s-1个后缀的lcp是|t|-|s|,那么说明这个s是靠谱的。可以用SA或者明天要学的Z函数来求。

想想怎么用前缀函数来检查:

  1. |s|和|t|的大小关系满足。
  2. 前2|s|个字符的周期是|s|的因数
  3. t[0..∣t∣−2∣s∣−1]=t[2∣s∣..∣t∣−1]t[0..|t|-2|s|-1]=t[2|s|..|t|-1]t[0..t2s1]=t[2s..t1]

前两点都好检查,至于第三点,显然最后剩下的后缀是t的一个候选border,可以从j=pi[|t|-1]开始不断让j=pi[j-1],观察是否有一个等于|t|-2|s|的时候。这个做法感觉比较慢,先写写试试。


AC了,这道题目放在kmp这里主要就是考察如何求候选border。学会扩展kmp后再来看看。

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 2048, MOD = 1000000007;

char save[M];
int fail[M];
void get_fail(char *save)
{
	fail[0] = 0;
	for(int i=1; save[i]; ++i)
	{
		int j = fail[i-1];
		while(j && save[i]!=save[j]) j=fail[j-1];
		if(save[i]==save[j]) ++j;
		fail[i] = j;
	}
}
int cal_period(int pos)
{
	if(pos % (pos - fail[pos-1]))
		return pos;
	return pos-fail[pos-1];
}
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int T = read();
	while(T--)
	{
		scanf("%s",save);
		int tn = strlen(save), sn;
		get_fail(save);
		for(sn=1; sn<=tn; ++sn) 
		{
			if(tn<2*sn || tn>=3*sn) continue;
			if(sn % cal_period(sn*2)) continue; //如果2s的周期不是sn的因数,显然不行

			int suf = tn - sn*2, j = fail[tn-1];
			while(j && suf != j)
				j = fail[j-1];
			if(suf==j) break; //找到了
		}
		for(int i=tn; i<tn+8; ++i)
			putchar(save[i%sn]);
		printf("...\n");
	}

    return 0;
}


inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值