【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;
}