分析
TJOI白给题
建出sam,对于每个点如果它的子树siz和等于k
那么对于这个满足的点它有贡献的长度一定是一个连续区间
直接差分即可
代码
#include<bits/stdc++.h> using namespace std; int n,k,mx,ans,d[100100]; char s[100100]; struct SAM { int mp[200100][30],fa[200100],ed,ccnt,len[200100],siz[200100]; int head[200100],nxt[200100],to[200100],cnt; inline void init(){ mx=0; cnt=ans=0; ccnt=ed=1; memset(d,0,sizeof(d)); memset(mp,0,sizeof(mp)); memset(fa,0,sizeof(fa)); memset(to,0,sizeof(to)); memset(len,0,sizeof(len)); memset(siz,0,sizeof(siz)); memset(nxt,0,sizeof(nxt)); memset(head,0,sizeof(head)); } inline void add(int x,int y){ nxt[++cnt]=head[x]; head[x]=cnt; to[cnt]=y; } inline void ins(int x,int n1){ int p=ed; ed=++ccnt; siz[ccnt]=1; len[ccnt]=n1; while(p&&!mp[p][x]){ mp[p][x]=ed; p=fa[p]; } if(!p){ fa[ed]=1; return; } int q=mp[p][x]; if(len[q]==len[p]+1){ fa[ed]=q; return; } len[++ccnt]=len[p]+1; for(int i=1;i<=26;i++)mp[ccnt][i]=mp[q][i]; fa[ccnt]=fa[q]; fa[q]=ccnt; fa[ed]=ccnt; for(int i=p;mp[i][x]==q;i=fa[i])mp[i][x]=ccnt; } inline void build(){ for(int i=2;i<=ccnt;i++)add(fa[i],i); } inline void dfs(int x){ for(int i=head[x];i;i=nxt[i]) dfs(to[i]),siz[x]+=siz[to[i]]; if(siz[x]==k&&len[fa[x]]+1<=len[x])d[len[fa[x]]+1]++,d[len[x]+1]--; } }; SAM sam; int main(){ int i,j,t; scanf("%d",&t); while(t--){ sam.init(); scanf("%s",s+1); n=strlen(s+1); scanf("%d",&k); for(i=1;i<=n;i++)sam.ins(s[i]-‘a‘+1,i); sam.build(); sam.dfs(1); for(i=1;i<=n;i++){ d[i]+=d[i-1]; if(d[i]&&d[i]>=mx){ mx=d[i]; ans=i; } } printf("%d\n",ans?ans:-1); } return 0; }
原文地址:https://www.cnblogs.com/yzxverygood/p/11519053.html
时间: 2024-08-30 18:22:19