p5341 [TJOI2019]甲苯先生和大中锋的字符串

分析

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值