zoukankan      html  css  js  c++  java
  • 序列自动机 浅谈

    其实这个东西真的算自动机吗?好像还真的符合自动机的定义啊;

    我将在下面用人话来定义序列自动机,并不像某度某科一样不说人话;

    设一个字符集S,nxt[i][j]表示第i个位置往后第一个j元素出现的位置;

    这个nxt数组可以O(n)的求出来,可以自行验证;

    for(int i=n-1;i>=0;--i){
        for(int j=1;j<=26;++j) nxt[i][j]=nxt[i+1][j];
        nxt[i][s[i+1]-'a'+1]=i+1;
    }

    我们会发现一个神奇的事情:这是一个DAG!

    她能干什么事情呢?

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

    当我们构造出nxt数组之后,可以贪心的寻找子序列;

    2.求一个序列的子序列个数;(可以限定序列的长度)

    我们在DAG上跑拓扑DP,f[v][j]表示从1~v寻则j个元素的方案数;

    显然的:f[v][j]+=f[u][j-1];

    #include <bits/stdc++.h>
    #define inc(i,a,b) for(register int i=a;i<=b;i++)
    #define dec(i,a,b) for(register int i=a;i>=b;i--)
    using namespace std;
    char s[3010];
    int nxt[3010][40];
    int n,m;
    long long f[3010][3010];
    int rudu[3010];
    const int p=998244353;
    queue<int> qwq;
    void tp()
    {
    	qwq.push(0);
    	f[0][0]=1;
    	while(qwq.size()){
    		int u=qwq.front();
    		qwq.pop();
    		inc(i,0,25){
    			if(!nxt[u][i]) continue;
    			inc(j,0,u) f[nxt[u][i]][j+1]=(f[nxt[u][i]][j+1]+f[u][j])%p;
    			--rudu[nxt[u][i]];
    			if(rudu[nxt[u][i]]==0) qwq.push(nxt[u][i]);
    		}
    	}
    }
    int main()
    {
    	scanf("%s",s+1);
    	n=strlen(s+1);cin>>m;
    	dec(i,n-1,0){
    		inc(j,0,25) nxt[i][j]=nxt[i+1][j];
    		nxt[i][s[i+1]-'a']=i+1;
    		inc(j,0,25) if(nxt[i][j]!=0) rudu[nxt[i][j]]++;
    	}
    	tp();	
        long long ans=0;
    	inc(i,1,n) ans=(ans+f[i][m])%p;
    	cout<<ans%p;
    }
    /*
    addeade
    3
    
    aa
    1
    */
    

     

    3.求两串的公共子序列个数

    两串都构造一下,直接跑就好了

    long long dfs(int x,int y){
        if(f[x][y]) return f[x][y];
        for(int i=1;i<=26;++i)
            if(nxt1[x][i]&&nxt2[y][i])
                f[x][y]+=Dfs(nxt1[x][i],nxt2[y][i]);
        return ++f[x][y];
    }
    

     

    4.求字符串的回文子序列个数

     首先原串与反串都建一遍;

    就相当于从左右端点向中间跑自动机;

    显然:x+y<=n+1才会合法;

    但要注意,我们只能统计偶数长度的字符串,而不能统计奇数个数的字符串;

    因为我们永远都是两个两个地串;

    long long Dfs(int x,int y){
        if(f[x][y]) return f[x][y];
        for(int 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];
    }
    

    DAG

  • 相关阅读:
    HIVE入门
    Mapreduce中的reduce数量和分区控制
    MapReduce入门2-流量监控
    MapReduce入门
    树莓派保持网络连接shell脚本
    手动转屏
    Shell教程
    6个基本screen命令
    node.js 开发博客系统
    iap 应用内购买相关的解释
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11823052.html
Copyright © 2011-2022 走看看