SP263 PERIOD - Period KMP技巧

\(\color{#0066ff}{题目描述}\)

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

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

\(\color{#0066ff}{输入格式}\)

第一行一个T,T组数据\(T \leq 10\)

每组数据一个n,\(n\leq 1000000\),表示字符串长度

接下来是字符串

\(\color{#0066ff}{输出格式}\)

每组数据输出前缀长度以及最大循环次数

\(\color{#0066ff}{输入样例}\)

2
3
aaa
12
aabaabaabaab

\(\color{#0066ff}{输出样例}\)

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

\(\color{#0066ff}{题解}\)

kmp的nxt数组为后缀与前缀相同的最长长度(可重叠!!)

因此,如果当前前缀合法,那么i-nxt[i]一定是最小循环长度,所以i/(i-nxt[i])就是次数喽

#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define _ 0
#define LL long long
#define Space putchar(' ')
#define Enter putchar('\n')
#define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
#define fu(x,y,z)  for(int x=(y),x##end=z;x<x##end;x++)
#define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
#define fd(x,y,z)  for(int x=(y),x##end=z;x>x##end;x--)
#define mem(x,y)   memset(x,y,sizeof(x))
#ifndef olinr
inline char getc()
{
	static char buf[100001],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
template<typename T>inline void in(T &x)
{
	int f=1; char ch; x=0;
	while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
	while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
	x*=f;
}
int n,m;
struct node
{
	int to;
	node *nxt;
};
typedef node* nod;
nod head[1500];
int to[1500];
bool vis[1500];
int tot;
int ans[1060];
inline void add(int from,int to)
{
	nod t=new node;
	t->to=to;
	t->nxt=head[from];
	head[from]=t;
}
inline bool find(int x)
{
	for(nod i=head[x];i;i=i->nxt)
	{
		if(!vis[i->to])
		{
			vis[i->to]=true;
			if((!(~to[i->to]))||find(to[i->to]))
			{
				to[i->to]=x;
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
	in(n),in(m);
	int x,y;
	fuu(i,0,m-1) in(x),in(y),add(i,x),add(i,y),ans[i]=-1;
	fuu(i,0,std::max(n,m)-1) to[i]=-1;
	fuu(i,0,m-1)
	{
		mem(vis,0);
		if(find(i)) tot++;
		else break;
	}
	printf("%d\n",tot);
	fuu(i,0,n-1) if(~to[i]) ans[to[i]]=i;
	fuu(i,0,m-1) if(~ans[i]) printf("%d\n",ans[i]);
	return ~~(0^_^0);
}
posted @ 2018-11-30 20:18  olinr  阅读(249)  评论(0编辑  收藏  举报