zoukankan      html  css  js  c++  java
  • [TJOI2019]甲苯先生和大中锋的字符串——后缀自动机+差分

    题目链接:

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

    对原串建后缀自动机并维护$parent$树上每个点的子树大小,显然子树大小为$k$的节点所代表的子串出现过$k$次,那么我们需要将$[len[fa[i]]+1,len[i]]$这一段区间的数目都$+1$,只需要差分即可,最后求前缀和并求出所有前缀和的最大值的位置即为答案。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int T;
    char ch[100010];
    int n,k;
    int s[100010];
    int last;
    int tr[200010][26];
    int len[200010];
    int pre[200010];
    int head[200010];
    int next[200010];
    int to[200010];
    int tot;
    int cnt;
    int size[200010];
    void add(int x,int y)
    {
        next[++tot]=head[x];
        head[x]=tot;
        to[tot]=y;
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=next[i])
        {
            dfs(to[i]);
            size[x]+=size[to[i]];
        }
    }
    void init()
    {
        memset(s,0,sizeof(s));
        memset(tr,0,sizeof(tr));
        memset(len,0,sizeof(len));
        memset(pre,0,sizeof(pre));
        memset(head,0,sizeof(head));
        memset(size,0,sizeof(size));
        tot=0;
        last=cnt=1;
    }
    void insert(int x)
    {
        int p=last;
        int np=++cnt;
        last=np;
        size[np]++;
        len[np]=len[p]+1;
        for(;p&&!tr[p][x];p=pre[p])
        {
            tr[p][x]=np;
        }
        if(!p)
        {
            pre[np]=1;
        }
        else
        {
            int q=tr[p][x];
            if(len[q]==len[p]+1)
            {
                pre[np]=q;
            }
            else
            {
                int nq=++cnt;
                len[nq]=len[p]+1;
                pre[nq]=pre[q];
                memcpy(tr[nq],tr[q],sizeof(tr[q]));
                pre[np]=pre[q]=nq;
                for(;p&&tr[p][x]==q;p=pre[p])
                {
                    tr[p][x]=nq;
                }
            }
        }
    }
    void solve()
    {
        scanf("%s%d",ch+1,&k);
        n=strlen(ch+1);
        for(int i=1;i<=n;i++)
        {
            insert(ch[i]-'a');
        }
        for(int i=2;i<=cnt;i++)
        {
            add(pre[i],i);
        }
        dfs(1);
        for(int i=1;i<=cnt;i++)
        {
            if(size[i]==k)
            {
                s[len[pre[i]]+1]++;
                s[len[i]+1]--;
            }
        }
        int sum=0;
        int mx=0;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            sum+=s[i];
            if(sum>=mx)
            {
                mx=sum,ans=i;
            }
        }
        printf("%d
    ",mx>0?ans:-1);
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
    }
  • 相关阅读:
    shell的一本书
    linux设置网络三种方法
    BIOS讲解
    对于ssh和hadoop联系讲解和ssh的基本内容
    Httphandler
    ASP.NET配置文件
    Httpmoudle
    ASP.NET页面生命周期
    ASP.NET页面跳转方法的集合
    OutputCache的使用
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10836105.html
Copyright © 2011-2022 走看看