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

  • 相关阅读:
    打开安装 好的Microsoft Dynamics CRM 4.0 报错误为 Caller does not have enough privilege to set CallerOriginToken to the specified value 的解决办法
    基于 Windows Server 2008 的计算机对 Microsoft Dynamics CRM 4.0 的支持
    Microsoft Dynamics CRM 4.0 如何添加自定义按钮
    Microsoft Dynamics CRM 4.0 Plugin 取值,赋值,查询
    C# 中的 enum(枚举) 类型使用例子
    vue事件的绑定
    表单验证2
    node中模块
    node模块的引入
    node中的读文件
  • 原文地址:https://www.cnblogs.com/cutemush/p/12627545.html
Copyright © 2011-2022 走看看