zoukankan      html  css  js  c++  java
  • 【洛谷5826】【模板】子序列自动机

    点此看题面

    • 给定一个长度为(n)的文本串,字符集大小为(m)
    • (q)次询问,每次给定一个字符串,询问是否为文本串的一个子序列。
    • (n,m,qle10^5)

    思想核心:贪心

    其实就这题而论,子序列自动机是一个非常简单易懂的算法,闲得无聊来水一水。

    核心思想是贪心,就是考虑我们每次找到尽可能近的字符匹配一定是最优的。

    方法一:主席树

    由于常见字符串问题的字符集大小是(26),所以相信大家都写过一个东西,就是记录(S_{i,c})表示第(i)位之后第一个字符(c)所在位置。

    要维护这个只需从后往前枚举,每次(S_i)继承(S_{i+1}),并更新(S_{i,a_{i+1}}=i+1)

    这题字符集很大,考虑继承操作就相当于是一个版本的赋值,随后我们进行的是在新版本上的一个单点修改。

    发现这就是一个用主席树实现可持久化数组的过程,非常板子。

    方法二:(vector)+二分

    直接对于每个字符集开一个(vector),要找到第(i)位之后第一个字符(c),只要在字符(c)对应的(vector)中求出(upper\_bound(i))即可。

    而且把(vector)换成(set)甚至能实现带修,这是主席树做不到的。所以说主席树直接被全方位吊打。

    代码:(O(nlogn))

    当然是方法二啦,不会真的有人会去写主席树吧。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    using namespace std;
    int n,m;vector<int> S[N+5];vector<int>::iterator it;
    int main()
    {
    	RI Qt,i,x,y;for(scanf("%d%d%d%d",&x,&n,&Qt,&m),i=1;i<=n;++i) scanf("%d",&x),S[x].emplace_back(i);//对每种字符维护个vector
    	RI t;W(Qt--) {for(scanf("%d",&t),x=0;t;--t) scanf("%d",&y),
    		~x&&(x=(it=upper_bound(S[y].begin(),S[y].end(),x))==S[y].end()?-1:*it);puts(~x?"Yes":"No");}//利用upper_bound查找下一位
    	return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/SubSeqAutomation.html
Copyright © 2011-2022 走看看