洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]

  题目传送门

A Horrible Poem

题目描述

Bytie boy has to learn a fragment of a certain poem by heart. The poem, following the best lines of modern art, is a long string consisting of lowercase English alphabet letters only. Obviously, it sounds horrible, but that is the least of Bytie's worries.

First and foremost, he completely forgot which fragment is he supposed to learn. And they all look quite difficult to memorize...

There is hope, however: some parts of the poem exhibit certain regularity. In particular, every now and then a fragment, say 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash], is but a multiple repetition of another fragment, say 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] (in other words, 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash], i.e., 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash], where 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] is an integer). In such case we say that 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] is a full period of 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] (in particular, every string is its own full period).

If a given fragment has a short full period, Bytie's task will be easy. The question remains... which fragment was that?

Make a gift for Bytie - write a program that will read the whole poem as well as a list of fragments that Bytie suspects might be the one he is supposed to memorize, and for each of them determines its shortest full period.

给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节。

如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到。

输入输出格式

输入格式:

In the first line of the standard input there is a single integer 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] (洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]).

In the second line there is a string of length 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] consisting of lowercase English alphabet letters-the poem.

We number the positions of its successive characters from 1 to 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash].

The next line holds a single integer 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] (洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]) denoting the number of fragments.

Then the following 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] lines give queries, one per line.

Each query is a pair of integers 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] and 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] (洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]), separated by a single space, such that the answer to the query should be the length of the shortest full period of the poem's fragment that begins at position 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] and ends at position 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash].

In tests worth in total 42% of the points 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] holds in addition.

In some of those, worth 30% of points in total, 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] holds as well.

输出格式:

Your program should print 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash] lines on the standard output.

The 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]-th of these lines should hold a single integer - the answer to the 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]-th query.

输入输出样例

输入样例#1:
8
aaabcabc
3
1 3
3 8
4 8
输出样例#1:
1
3
5

说明

给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节。

如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到。


  分析:

  一道稍考思维的字符串题目,一开始没想到第三条性质只能打出暴力。

  本道题共有三个重要的性质,只要能想到也就不难写出来了:

  1,循环节长度一定是区间长度的约数

  2,如果n是一个循环节长度,那么k*n(当然k*n也要是区间长度的约数)也会是一个循环节长度

  3,满足一个子串为该段字符串区间的循环节的充要条件是$[l,r-t]$与$[l+t,r]$的$hash$值相同,其中$t$是该子串的长度

  有了上面三条性质也就不难做了。

  首先预处理出$n$范围内的质因数,然后从大到小枚举区间长度的质因数,用性质3计算该长度的子串是不是循环节即可。当然,预处理需要用优化版的埃氏筛,否则会被愉快地T飞。。。

  Code:

//It is made by HolseLee on 10th Aug 2018
//Luogu.org P3538
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#pragma GCC optimize(2)
using namespace std; typedef unsigned long long ull;
const int N=5e5+;
const ull base=;
ull h[N],a[N];
int n,m,nxt[N],q[N<<];
char s[N];
bool vis[N]; inline int read()
{
char ch=getchar();int num=;
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<=''){
num=num*+ch-'';ch=getchar();
}
return num;
} inline void print(int x)
{
if(x>)print(x/);
putchar(x%+'');
} void divisor()
{
int top=;
for(int i=;i<N;++i){
if(vis[i]){
for(int j=;j<=top&&(ull)(i*q[j])<N;++j){
nxt[i*q[j]]=q[j],
vis[i*q[j]]=true;
if(i%q[j]==)break;
}
}
else {
vis[q[++top]=i]=true;nxt[i]=i;
for(int j=;j<=top&&(ull)(i*q[j])<N;++j){
nxt[i*q[j]]=q[j],
vis[i*q[j]]=true;
}
}
}
} inline bool check(int l1,int r1,int l2,int r2)
{
return ((h[r1]-h[l1-]*a[r1-l1+])==(h[r2]-h[l2-]*a[r2-l2+]));
} int main()
{
n=read();
scanf("%s",s+);
for(int i=;i<=n;++i){
h[i]=h[i-]*base+s[i]-'a'+;
}
a[]=;
for(int i=;i<=n;++i){
a[i]=a[i-]*base;
}
divisor();
m=read();
int l,r,tot,len,t;
for(int i=;i<=m;++i){
l=read(),r=read();
len=r-l+;tot=;
while(len!=){
q[++tot]=nxt[len];
len/=nxt[len];
}
len=r-l+;
for(int j=;j<=tot;++j)
if(len>=q[j]){
t=len/q[j];
if(check(l,r-t,l+t,r)){
len=t;
}
}
print(len);putchar('\n');
}
return ;
}
上一篇:Linux内核参数配置


下一篇:python 学习笔记十三 JQuery(进阶篇)