洛谷 SP263 Period

洛谷 SP263 Period

题目描述

For each prefix of a given string *S* with *N* characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each *i* (2 <= *i* <= *N*) we want to know the largest *K* > 1 (if there is one) such that the prefix of *S* with length *i* can be written as *A* ^{K}*K* , that is *A* concatenated *K* times, for some string *A*. Of course, we also want to know the period *K*.

输入格式

The first line of the input file will contains only the number T (1 <= T <= 10) of the test cases.

Each test case consists of two lines. The first one contains *N* (2 <= *N* <= 1 000 000) – the size of the string *S*. The second line contains the string *S*.

输出格式

For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.

题意翻译

如果一个字符串S是由一个字符串T重复K次形成的,则称T是S的循环元。使K最大的字符串T称为S的最小循环元,此时的K称为最大循环次数。

现给一个给定长度为N的字符串S,对S的每一个前缀S[1~i],如果它的最大循环次数大于1,则输出该前缀的最小循环元长度和最大循环次数。

感谢@super_kidding 提供的翻译

输入输出样例

输入 #1复制

输出 #1复制


一道KMP算法的练手好题。

大体的题目大意是这样的:

题目大意:

如果一个字符串S是由一个字符串T重复K次形成的,则称T是S的循环元。使K最大的字符串T称为S的最小循环元,此时的K称为最大循环次数。

现给一个给定长度为N的字符串S,对S的每一个前缀S[1~i],如果它的最大循环次数大于1,则输出该前缀的最小循环元长度和最大循环次数。

题解:

一道KMP算法的题目,如果对KMP算法还是没有什么深刻的理解或者还没学KMP算法的,请移步我的这篇博客,讲解还算详细:

KMP算法详解

一开始拿到题没什么思路(我还是太菜了)

后来发现,对给出的串S自匹配求出nxt数组之后,对于每一个i,一定会有这么一个结论:

S[1tonxt[i]]=S[inxt[i]+1toi]

这是通过KMP算法对nxt数组的定义得来的。

那么,既然这两个东西是相等的,那么在对这个子串进行匹配的时候,这个循环节长度就应该是inxt[i],然后循环次数当然就是i/(inxt[i]),当然,前提需要是i%(inxt[i])==0

代码如下:

#include<cstdio>
using namespace std;
const int maxl=1e6+10;
int n,tot;
char s[maxl];
int nxt[maxl];
int main()
{
    while(~scanf("%d",&n) && n)
    {
        scanf("%s",s+1); 
        tot++;
        printf("Test case #%d\n",tot);
        nxt[1]=0;
        for(int i=2,j=0;i<=n;++i)
        {
            while(s[i]!=s[j+1] && j) 
                j=nxt[j];
            if(s[i]==s[j+1]) 
                j++;
            nxt[i]=j;
            if(nxt[i]!=0 && i%(i-nxt[i])==0) 
                printf("%d %d\n",i,i/(i-nxt[i]));
        }
        printf("\n");
    }
    return 0;
}
posted @   Seaway-Fu  阅读(178)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示