zoukankan      html  css  js  c++  java
  • 序列自动机入门

    Prob1

    给你一个长度为1000000字符串s
    然后给你1000000个问题
    问a是不是s的子序列

    Sol:

    序列自动机是用来判断是否是子序列的算法 时间复杂度是 O(len)

    nx[i][j] 数组存的是在 s 中第 i 位后面第一个 j 字母出现的位置

    Prog:

    #include<bits/stdc++.h>
    #define rint register int
    #define deb(x) cerr<<#x<<" = "<<(x)<<'
    ';
    using namespace std;
    typedef long long ll;
    typedef pair <int,int> pii;
    const ll mod = 1e9 + 7;
    const int maxn = 1e6 + 10;
    int n, t, nxt[maxn][30];
    char s[maxn], str[maxn];
    
    int main() {
    	scanf("%s", s+1);
    	int len = strlen(s+1);
    	for(int i=len; i; i--) //逆循环 
    	{
    		for(int j=0; j<26; j++) //26个字母 
    		    nxt[i-1][j] = nxt[i][j];
    		nxt[i-1][s[i]-'a'] = i;
    	}
    	int a,b;
    /*	while (true)
    	{
    		cin>>a>>b;
    		cout<<nxt[a][b]<<endl;
    		
    	 } 
    */
    	scanf("%d", &t);
    	while(t--)
    	{
    		scanf("%s", str);
    		int lenc = strlen(str), f = 0;
    		for(int i=0, now=0; i<lenc; i++)
    		{
    			now = nxt[now][str[i]-'a'];
    			if(!now) 
    			{
    				f = 1;
    				break;
    			}
    		}
    		if(f) puts("No");
    		else puts("Yes");
    	}
    }
    

      

    Prob2:给出一个字符串统计其本质不同的子序列个数

    SOL:记忆化搜索

    #include<bits/stdc++.h>
    #define rint register int
    #define deb(x) cerr<<#x<<" = "<<(x)<<'
    ';
    using namespace std;
    typedef long long ll;
    typedef pair <int,int> pii;
    const ll mod = 1e9 + 7;
    const int maxn = 3e3 + 10;
    int n, nxt[maxn][30], f[maxn];
    char s[105];
    
    int dfs(int x) {
    	if(f[x]) 
    	   return f[x];
    	for(int i=0; i<26; i++)
    		if(nxt[x][i]) f[x] += dfs(nxt[x][i]);
    	return ++f[x];
    }
    
    int main() {
    	scanf("%d%s", &n, s+1);
    	for(int i=n; i; i--) {
    		for(int j=0; j<26; j++) nxt[i-1][j] = nxt[i][j];
    		nxt[i-1][s[i]-'a'] = i;
    	}
    	int num = dfs(0);
    	printf("%d
    ", num);
    }
    

    另一个做法:

    zz https://blog.csdn.net/weixin_35338624/java/article/details/88571242

    https://blog.csdn.net/oranges_c/article/details/53364269?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

    Leetcode 940:不同的子序列II

    题目描述
    给定一个字符串 S,计算 S 的不同非空子序列的个数。
    因为结果可能很大,所以返回答案模 10^9 + 7.

    示例 1:

    输入:"abc"

    输出:7
    解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。


    示例 2:

    输入:"aba"
    输出:6
    解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。


    示例 3:

    输入:"aaa"
    输出:3
    解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。

    提示:

    S 只包含小写字母。
    1 <= S.length <= 2000
    解题思路
    动态规划,dp[i]定义为以i位置字母结尾的不同子序列个数,当没个字母唯一出现一次时,状态转换方程为dp[i+1] = 2*dp[i],但是根据题目示例,会出现重复的子序列,于是用last[26]记录每个S中的字母最后一次出现的位置,当某一个字母至少出现一次时使用dp[i+1]减去相应的数目就行

    int distinctSubseqII(string S) {
            int len=S.length();
            int mod = 1e9+7;
            int dp[len+1] = {0};
            int last[26];
            memset(last,-1,sizeof(last));
            dp[0]=1;
            for(int i=0;i<len;i++){
                dp[i+1]=(2*dp[i])%mod;
                int idx=S[i]-'a';
                if(last[idx]>=0){
                    dp[i+1]=(dp[i+1]-dp[last[idx]] + mod)%mod;
                }
                last[idx]=i;
            }
            dp[len] = (dp[len]-1)%mod;
            return dp[len];
        }
    

      当然此题还可以用后缀数组,后缀自动机等方法来完成 .

    可参考:https://blog.csdn.net/weixin_41863129/article/details/95060033

  • 相关阅读:
    从头认识java-2.2 算术操作符
    从头认识java-2.1 操作符
    从头认识java-1.8 创建和操纵对象(2)
    从头认识java-1.8 创建和操纵对象(1)
    从头认识java-1.7 单根继承与集合
    从头认识java-1.6 多态
    从头认识java-目录
    颜色
    内部CSS
    外部CSS
  • 原文地址:https://www.cnblogs.com/cutemush/p/12627545.html
Copyright © 2011-2022 走看看