题解 SP687【REPEATS - Repeats】
题意
给出一个长度为 $n$ 的字符串 $s$,求最大的 $k$ 使得 $s$ 有子串满足其是由任意一个字符串 $t$ 重复拼接 $k$ 次而成的。多组数据。
$T\le 20,n\le 5\times 10^4$。
思路
这是一篇 $\text{SAM}$ 题解!
与我同样做法的题解可能说得不是很清楚(我不太看得懂),于是我也来写一篇。
根据 P4391 的结论,我们可以往 $\text{border}$ 的方向考虑。
如果我们枚举 $\text{border}$,设前缀为 $A=s[l,q]$,后缀为 $A=s[p,r]$,总串为 $B=s[l,r]$,我们要求 $p\le q$。由 P4391 的结论,我们知道 $s[l,r]$ 是可以由 $s[q+1,r]$ 重复并截取一个后缀得到。这里我们要忽略最后被截掉的部分,得到重复次数是 $\displaystyle\lfloor\dfrac{r-l+1}{r-q}\rfloor$。
考虑这个 $\text{border}$ 是 $s$ 的一个子串,如果要枚举 $\text{border}$ 并且求出它在 $s$ 中的结束位置,我们自然会选择 $\text{SAM}$。
建出 $\text{SAM}$ 后,我们枚举结点 $i$,考虑它作为 $\text{border}$ 时的贡献。由于我们要知道结束位置相关的信息,需要线段树合并求出 $\text{endpos}$。为了方便,我们将上文中式子转化为 $\displaystyle\lfloor\dfrac{q-l+1}{r-q}\rfloor+1$,自然,我们要让 $q-l+1$ 最大且 $r-q$ 最小。易得,$q-l+1$ 的最大值是 $len_i$,$r-q$ 的最小值是在 $\text{endpos}$ 中的任意两个元素 $x,y(x<y)$,$y-x$ 的最小值。对于后者,我们直接在线段树上维护即可。
于是我们就得到了这个结点的贡献 $\displaystyle\lfloor\dfrac{len_i}{\min_{x,y\in\text{endpos}(i),x<y}(y-x)}\rfloor+1$。对所有的贡献取 $\max$ 即可。
时间复杂度 $O(\sum n\log n)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e5+10;
struct node{
int ml,mr,md;
inline friend node operator+(const node &a, const node &b){
node c;
c.ml=min(a.ml,b.ml),c.mr=max(a.mr,b.mr);
c.md=min({a.md,b.md,b.ml-a.mr});
return c;
}
node(){ ml=md=1e9,mr=0; }
};
struct Edge{
int to,nxt;
}b[N];
int T,n,ans;
int head[N],cnt;
inline void add(int u,int v){
cnt++;
b[cnt].to=v;
b[cnt].nxt=head[u];
head[u]=cnt;
}
struct Segument_Tree{
int son[2][N*20],root[N],cnt;
node mes[N*20];
#define ls (son[0][rt])
#define rs (son[1][rt])
inline void pushup(int rt){
mes[rt]=mes[ls]+mes[rs];
}
inline void insert(int &rt,int l,int r,int p){
if(!rt)
rt=++cnt;
if(l==r){
mes[rt].ml=mes[rt].mr=l;
mes[rt].md=1e9;
return ;
}
int mid=l+r>>1;
if(p<=mid) insert(ls,l,mid,p);
else insert(rs,mid+1,r,p);
pushup(rt);
}
inline int merge(int a,int b,int l,int r){
if(!a||!b) return a+b;
int rt=++cnt;
if(l==r) return rt;
int mid=l+r>>1;
ls=merge(son[0][a],son[0][b],l,mid);
rs=merge(son[1][a],son[1][b],mid+1,r);
pushup(rt);
return rt;
}
inline int query(int rt){
return mes[rt].md;
}
inline void clear(){
for(int i=1;i<=cnt;i++)
mes[i]=node(),son[0][i]=son[1][i]=0;
cnt=0;
}
}t;
struct SAM{
struct statu{
int len,link;
int ch[26];
}a[N];
int siz,last;
SAM(){
a[0].len=0;
a[0].link=-1;
last=0;
}
inline void insert(int c,int i){
int cur=++siz;
a[cur].len=a[last].len+1;
t.insert(t.root[cur],1,n,i);
int p=last;
while(p!=-1&&!a[p].ch[c]){
a[p].ch[c]=cur;
p=a[p].link;
}
if(~p){
int q=a[p].ch[c];
if(a[p].len+1==a[q].len){
a[cur].link=q;
}else{
int clone=++siz;
a[clone]=a[q];
a[clone].len=a[p].len+1;
while(p!=-1&&a[p].ch[c]==q){
a[p].ch[c]=clone;
p=a[p].link;
}
a[q].link=a[cur].link=clone;
}
}else{
a[cur].link=0;
}
last=cur;
}
inline void clear(){
for(int i=0;i<=siz;i++){
memset(a[i].ch,0,sizeof(a[i].ch));
a[i].len=a[i].link=0;
}
a[0].len=0,a[0].link=-1;
siz=last=0;
}
inline void build(int n){
static char str[N];
for(int i=1;i<=n;i++)
insert(getc()-'a',i);
for(int i=1;i<=siz;i++)
add(a[i].link,i);
}
inline void dfs(int rt){
for(int i=head[rt];i;i=b[i].nxt){
dfs(b[i].to);
t.root[rt]=t.merge(t.root[rt],t.root[b[i].to],1,n);
}
ans=max(ans,a[rt].len/t.query(t.root[rt])+1);
}
}sam;
inline void clear(){
for(int i=0;i<=sam.siz;i++)
t.root[i]=head[i]=0;
sam.clear(),t.clear();
cnt=0;
}
int main(){
T=read();
while(T--){
n=read(),ans=0;
sam.build(n);
sam.dfs(0);
write(ans),putc('\n');
clear();
}
flush();
return 0;
}
再见 qwq~

浙公网安备 33010602011771号