Luogu5826 【模板】子序列自動機
阿新 • • 發佈:2020-07-20
子序列自動機
首先考慮\(O(nm)\)的暴力
\(nxt[i][j]\)表示\(i\)之後\(j\)出現的最前位置,很容易處理(具體看程式碼)
匹配子串一個個跳過去就好了(同上,具體看程式碼)
C++ Code:
#include<bits/stdc++.h> using namespace std; int opt,n,q,m,g,w,k; int nxt[100005][105],a[100005]; bool flag; int main() { scanf("%d%d%d%d",&opt,&n,&q,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=m;i++) nxt[n][i]=-1; for (int i=n;i;i--) { for (int j=1;j<=m;j++) nxt[i-1][j]=nxt[i][j]; nxt[i-1][a[i]]=i; } while (q --> 0) { scanf("%d",&w); g=0; flag=false; for (int i=1;i<=w;i++) { scanf("%d",&k); if (!(~nxt[g][k])) flag=true; else g=nxt[g][k]; } puts(flag?"No":"Yes"); } return 0; }
考慮優化,我們求\(nxt\),可以用兩種方法處理
\(1.\)因為每次只改一個值,用主席樹維護
\(2.\)二分\(nxt\)的位置,將每個數的位置丟進該數的\(vector\)中,\(vector\)原本就是有序的,下面的程式碼是二分版的
C++ Code:
#include<bits/stdc++.h> #define N 100005 using namespace std; int opt,n,q,m,g,st,k,a[N]; vector<int>v[N]; bool flag; int find(int u,int c) { vector<int>::iterator pos=upper_bound(v[u].begin(),v[u].end(),c); if (pos==v[u].end()) return -1; else return *pos; } int main() { scanf("%d%d%d%d",&opt,&n,&q,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]),v[a[i]].push_back(i); for (;q --> 0;) { scanf("%d",&g); flag=false; st=0; for (;g --> 0;) { scanf("%d",&k); if (flag) continue; st=find(k,st); if (!(~st)) flag=true; } puts(flag?"No":"Yes"); } return 0; }