1 条题解

  • 0
    @ 2026-5-8 23:15:06

    SAM一道很裸的题。。。

    题意很明确,不再阐述。

    做法很简单:找到所有出现次数为 k k 的子串,然后统计。

    怎么找到这些字符串呢?SAM 只能找出等价类啊。

    注意 parent tree 的父亲节点的长度 +1 即该等价类中长度最短的字符串,那么若我们先通过拓扑排序求出每个等价类在原串中出现次次数 siz[u] siz[u] ,该等价类的所有字符串都出现了 siz[u] siz[u] 次,那么就变为了一个序列操作题:

    1. 区间加 1 1
    2. 查询前缀和 而所有 2 2 操作都在 1 1 操作之后,我们可以用 O(n) O(n) 的差分优秀地解决这个问题。

    贴代码:

    #include<cstring>
    #include<cstdio>
    const int M=1e5+5;
    int T,n,k,tot=1,lst=1,sum[M],id[M<<1],CB[M<<1],siz[M<<1];char s[M];
    struct Node{
        int chi[26];
        int f,len;
        Node():f(0),len(0){memset(chi,0,104);}
    }SAM[M<<1];
    inline void Insert(const int&s){
        int q,p,nq,np;
        p=lst;np=lst=++tot;
    	SAM[np].len=SAM[p].len+1;siz[np]=1;
        for(;p&&!SAM[p].chi[s];p=SAM[p].f)SAM[p].chi[s]=np;
        if(!p)SAM[np].f=1;
        else{
            q=SAM[p].chi[s];
            if(SAM[q].len==SAM[p].len+1)SAM[np].f=q;
            else{
                SAM[nq=++tot]=SAM[q];
                SAM[np].f=SAM[q].f=nq;
                SAM[nq].len=SAM[p].len+1;
                for(;p&&SAM[p].chi[s]==q;p=SAM[p].f)SAM[p].chi[s]=nq;
            }
        }
    }
    inline int Solve(){
        register int i,u,ans=n+1;
        for(i=1;i<=tot;++i)++CB[SAM[i].len];
        for(i=1;i<=tot;++i)CB[i]+=CB[i-1];
        for(i=1;i<=tot;++i)id[CB[SAM[i].len]--]=i;
        for(i=tot;i>=1;--i){
            u=id[i];
            siz[SAM[u].f]+=siz[u];
            if(siz[u]==k)++sum[SAM[u].len],--sum[SAM[SAM[u].f].len];
        }
        for(i=n;i>=1;--i){
        	sum[i]+=sum[i+1];
        	if(sum[i]>sum[ans])ans=i;
    	}
    	ans=sum[ans]?ans:-1;
        while(tot)id[tot]=CB[tot]=siz[tot]=0,SAM[tot--]=Node();
        for(i=1;i<=n;++i)sum[i]=0;
        tot=lst=1;
        return ans;
    }
    signed main(){
        register int i;
        scanf("%d",&T);
        while(T--){
            scanf("%s%d",s,&k);n=strlen(s);
            for(i=0;i<n;++i)Insert(s[i]-97),s[i]=0;
            printf("%d\n",Solve());
        }
    }
    
    • 1

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

    信息

    ID
    10514
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者