2021年度训练联盟热身训练赛第四场 I Slot Machines 字符串 KMP 周期

【2021年度训练联盟热身训练赛第四场】
I Slot Machines (字符串 KMP 周期)

【题目描述】
在这里插入图片描述
在这里插入图片描述
【输入描述】
在这里插入图片描述
【输出描述】
Your program is to write to standard output. Print two integers k and p in one line.
The following shows sample input and output for two test cases.

测试样例1

输入

6
612534 3157 423 3157 423 3157

输出

1 2

测试样例2

输入

9
1 2 1 3 1 2 1 3 1

输出

0 4

【题目分析】

这道题的本质其实是一道求周期的题目。我们可以把输入的数字看作是字符,用KMP算法来求周期。我们把输入数字的顺序倒过来,使用getnext函数预处理后,用以下for循环对字符串长度进行遍历,依次找到当前位置的字符串周期tp和起始位置tk。答案是求使k+p最小的k和p的值(若k+p相等则取p更小的),更新答案即可。

for(int i=len;i>=1;i--)
	{
		int tk=len-i;
		int tp=i-nxt[i];
		if(tk+tp<sum||tk+tp==sum&&tp<p)
		{
			sum=tk+tp;
			k=tk;p=tp;
		}
	}

完整AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int len,str[1000005];
int nxt[1000005];
void getnext(int *str)
{
	int i=0,j=-1;
	nxt[0]=-1;
	while(i<len)
	{
		if(j==-1||str[i]==str[j])
			nxt[++i]=++j;
		else
			j=nxt[j];
	}
	return;
}//KMP算法 
int main()
{
	scanf("%d",&len);
	for(int i=len-1;i>=0;i--)
		scanf("%d",&str[i]);
	getnext(str);
	int k,p,sum=1999999999;
	for(int i=len;i>=1;i--)
	{
		int tk=len-i;
		int tp=i-nxt[i];
		if(tk+tp<sum||tk+tp==sum&&tp<p)
		{
			sum=tk+tp;
			k=tk;p=tp;
		}
	}
	printf("%d %d\n",k,p);
	return 0;
}

之前俱乐部训练做过两道类似的题目:

大一暑假第三周训练 B Power Strings

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str[1000005];
int nxt[1000005];
void getnext(char *str)
{
	int i=0,j=-1;
	int len=strlen(str);//切记要先记录长度,否则会超时 
	nxt[0]=-1;
	while(i<len)
	{
		if(j==-1||str[i]==str[j])
			nxt[++i]=++j;
		else
			j=nxt[j];
	}
	return;
}
int main()
{
	while(~scanf("%s",str))
	{
		if(str[0]=='.') break;
		int len=strlen(str);
		getnext(str);
		int k=len-nxt[len]; 
		if(len%k==0)//是否存在最小周期k 
			printf("%d\n",len/k);
		else
			printf("1\n");
	}
	return 0;
}

大一暑假第三周周赛 C Cyclic Necklace

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str[100005];
int nxt[100005];
void getnext(char *str)
{
	int i=0,j=-1;
	int len=strlen(str);
	nxt[0]=-1;
	while(i<len)
	{
		if(j==-1||str[i]==str[j])
			nxt[++i]=++j;
		else
			j=nxt[j];
	}
	return;
}//KMP算法 
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",str);
		int len=strlen(str);
		bool same=1;
		for(int i=0;i<len-1;i++)
		{
			if(str[i]!=str[i+1])
			{
				same=0;
				break;
			}
		}
		if(same)
		{
			printf("0\n");
			continue;
		}//如果全是相同字符 
		getnext(str);
		if(nxt[len]==0)//如果最大相同前后缀为0 
			printf("%d\n",len);
		else
		{
			int zhouqi=len-nxt[len];
			int temp=zhouqi-len%zhouqi;
			if(temp==zhouqi)
				printf("0\n");
			else
				printf("%d\n",zhouqi-len%zhouqi);
		}
	}
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

球王武磊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值