1 条题解

  • 0
    @ 2025-8-24 22:14:42

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar y2823774827y
    喜欢D人的菜鸡

    搬运于2025-08-24 22:14:42,当前版本为作者最后更新于2019-12-18 19:24:44,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    更好的阅读体验

    序列自动机

    • 构造

    aa是字符集,s=n|s|=nnxt[i][j]nxt[i][j]表示ii以后的第一个字符jj的位置,00为根节点,整个图是一个DAGDAG

    for(LL i=n;i>=1;--i){
        for(LL j=1;j<=a;++j) nxt[i-1][j]=nxt[i][j];
        nxt[i-1][s[i]]=i;
    }
    
    • 扩展构建

    当字符集较大时,可套用可持久化,在叶子节点放一个idid,表示出边。

    相关例题: 字符串KK小子序列,可持久化序列自动机,维护节点大小。

    一步一步(从首到尾)走,有序确定code

    经典例题

    • 判断是否是原字符串的子序列

    构造出了nxtnxt后,从根跑一遍就好了。

    • 求子序列个数

    从根跑,记忆化搜索,f[x]f[x]为点xx为首的子序列个数,f[y]=(xysonf[x])+1f[y]=(\sum\limits_{x\in y'son}f[x])+1

    • 求两串的公共子序列个数

    两串都构造一下,之间跑就好了。

    LL Dfs(LL x,LL y){
        if(f[x][y]) return f[x][y];
        for(LL i=1;i<=a;++i)
            if(nxt1[x][i]&&nxt2[y][i])
                f[x][y]+=Dfs(nxt1[x][i],nxt2[y][i]);
        return ++f[x][y];
    }
    
    • 求字符串的回文子序列个数

    原串与反串都建一遍

    $$\begin{aligned}\longrightarrow 1~~2~~3~~4~~5~~6~~7~~8~~9~~10&\\ 10~~9~~8~~7~~6~~5~~4~~3~~2~~1&\longleftarrow\\ \end{aligned}$$

    就相当于从左右端点这样跑。

    求的时候显然x+yn+1x+y≤n+1这个序列才是合法的。

    x+y=n+1x+y=n+1时就是会合了一样,在之后的遍历过程会++f[x][y]++f[x][y],所以暂时不统计。

    但是其他情况我们都是匹配的两个字符,也就是只会统计abbaabba,而统计不了abaaba,所以在过程中++f[x][y]++f[x][y]

    LL Dfs(LL x,LL y){
    	if(f[x][y]) return f[x][y];
    	for(LL i=1;i<=a;++i)
    		if(nxt1[x][i]&&nxt2[y][i]){
    			if(nxt1[x][i]+nxt2[y][i]>n+1) continue;
    			if(nxt1[x][i]+nxt2[y][i]<n+1) f[x][y]++;
    			f[x][y]=(f[x][y]+Dfs(nxt1[x][i],nxt2[y][i]))%mod;
    		}
    	return ++f[x][y];
    }
    
    • 求一个A,BA,B的最长公共子序列SS,使得CCSS的子序列

    还是同样的Dfs(x,y,z)Dfs(x,y,z),表示一匹配到CCzz位。

    改变一下CC的构建方法

    for(LL i=1;i<=a;++i) nxt[n][i]=n;
    for(LL i=0;i<n;++i){
    	for(LL j=1;j<=a;++j) nxt[i][j]=i;
    	nxt[i][c[i+1]]=i+1;
    }
    
    • 1

    信息

    ID
    4830
    时间
    2000ms
    内存
    500MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者