[永続セグメントツリー] [P5826] [テンプレート]配列オートマトン
説明
シーケンスを考えると\(A \)がある\(Q \)の時間は毎回クエリー配列尋ねた\(B \)ではありません\(A \)シーケンスのを
制限事項
シーケンス\(A \)はもはやより(10 ^ 5 \)\、およびクエリー配列の長さを超えない\(10 ^ 6 \)は、クエリの数を超えません\(10 ^ 5 \)を
溶液
余談:私たちは紫に設定して問題を解決することの難しさについて、私は、紫にはおそらくないと思いますが、ボードのセグメントツリーは紫で存続することができます
アルゴリズム\(1 \)
クエリー配列について考える\(B \)が設けられており、(A \)\最長共通サブシーケンス\(A \)である添字配列が\(Z \)、明らか場合に限り(\ Z \)長さ\(| B | \)場合、\(B \)である\(\)配列です。法的シーケンス\(Zが\)よりがあるかもしれませんが、限り、私たちのように辞書順最小の長さを見つけるよう\(| B | \)シーケンス\(Z \) 、あなたは説明することができます(\ B)は\である\ (\)サブシーケンス、そうでない場合はありません。
最小の配列を見つけるために辞書を考える\(Zを\)のために、すなわち、貪欲選択することができる\(B \)に対応し得ることができる各プレフィックス(\ Z)\最後のシーケンス番号が、最小である\ (B \)プレフィックスのみ必要数追加\(\)を電流から\(\ Z)走査が最初に新しいスイープに等しく、シーケンスの最後のビットの後方位置値を続行、新しいデジタル位置、\(Z \)最後のシーケンス。そしてスキャン場合\(A \)最後に、見つかったことには正当がないことを意味していない\(Z \)従って、シーケンス\(B \)の代わりに、\(A \)サブシーケンスは。
この場合、各問い合わせである場合、アップスキャンする\(A \)合計時間複雑であるので、一度\(O(NQ + \ SUM L)\) 、サブタスクによって\(1 \) 、所望のスコア\(20〜 PTS \)
アルゴリズム\(2 \)
考えてみましょう\(A \)識別するために使用されるサブオートマトンを確立\(Aを\)すべてのシーケンスに。
また、使用のAlgorithm 1
考えは、文字列\(B \) 、私たちはただでそれを発見した(A \)\での最長共通部分列\(A \)辞書順最小の添字順番に\( Zは\) 、記述することができる)、(B \ \である(\ \)配列です。次いでため\(A \)は、新しい番号と一致する必要がある場合、すべての点で、に転送されるべきである\(A \) 、位置の最初の桁の後に明らかにように保証するために、\(Zを\)辞書式順序は最小限です。したがって、我々は、各位置の背面上の位置の最初の桁の数を加算した後に転送を維持しなければなりません。
我々は考える\(A \)最初のために、前方位置確立オートマトンまで裏面から一つずつ\(I \) 、位置最初の\(I - 1 \)を加えビット\(a_iを\)に転送されなければならないが\(I \)、および数は、他の添加に転送されるべきである\(a_iを\)後添加の数に位置。したがって、擬似コード
for i : m do
trans[n][i] <- -1
end
for i = n : 1 do
for j = 1 : m do
trans[i - 1][j] <- trans[i][j]
end
trans[i - 1][A[i]] <- i
end
前記\(N- \)代表\(A \)の長さ、\(M \)代表\(A \)の最大値が、\(トランス\)は、オートマトンの代わりに二次元アレイです。
ストリング一方\(B \)マッチング、単に\(B \)搬送ロボットマシンが再び実行に沿って自動機械が不足していない場合、\(Bが\)であり、(A \)\サブ、そうでない場合ではありません。
Function check:
pos <- 0
ret <- true
for i = 1 : L do
pos <- trans[pos][B[i]]
if pos == -1 then
ret <- false
break
endif
end
return ret
end Func
この構成オートマトン時間の複雑性を指摘(O(NM)\)\、複雑さが一致する(O(\ SUM L)\)\ので、合計時間の複雑\(O(NM + \和 L )\) 、サブタスクによって\(1 \)、\ (2 \)、所望のスコア\(PTS〜55 \) 。
アルゴリズム\(3 \)
建設オートマトンは、最初にそのノート\(I \)第一の位置( - 1 \ I)\位置のみ\(a_iを\)一つは、同じではありません- \(1 \ I)ビットシフトが最初のように見ることができます\(I \)我々は、自動機械時間計算の確立することを、転写位置を維持するために、各アレイから永続前方セグメントツリーを使用できるように、転写位置における位置に基づいて改変O(\ (N- \ログM)\) 、時間複雑度が一致している)(O(\ SUMのL \ログM)\ \。総時間の複雑\(O((N + \ L SUM)\ログM)\)サブタスク、所望の点の全てを介して、\(100 PTS〜\) 。
コード
アルゴリズム\(2 \)
コードから@ ** _ Jiaoyue半分振りかける花**
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define MAXN 200010
using namespace std ;
int L, N, M, Q, S[MAXN], nxt[MAXN][102] ;
void build(){
for (int i = 1 ; i <= M ; ++ i)
nxt[L + 2][i] = nxt[L + 1][i] = L + 2 ;
for (int i = L ; i ; -- i)
memcpy(nxt[i - 1], nxt[i], sizeof(nxt[i])), nxt[i - 1][S[i]] = i ;
}
int qr(){
char c = getchar() ;
int res = 0 ; while (!isdigit(c)) c = getchar() ;
while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ;
return res ;
}
int main(){
int i, j, k, emm ;
cin >> emm >> N >> Q >> M ; L = N ;
for (i = 1 ; i <= L ; ++ i) scanf("%d", &S[i]) ; build() ;
for (i = 1 ; i <= Q ; ++ i){
N = qr() ; int st = 0, ans = 0 ;
for (j = 1 ; j <= N ; ++ j){
k = qr(), st = nxt[st][k] ;
if (!st){
while (j < N)
++ j, emm = qr() ;
ans = 1 ;
}
// cout << st << endl ;
}
printf(ans ? "No\n" : "Yes\n") ;
}
return 0 ;
}
アルゴリズム\(3 \)
#include <cstdio>
template <typename T>
inline void qr(T &x) {
char ch;
do ch = getchar(); while ((ch > '9') || (ch < '0'));
do x = x * 10 + (ch ^ 48), ch = getchar(); while ((ch >= '0') && (ch <= '9'));
}
const int maxn = 100005;
struct Tree {
Tree *ls, *rs;
int l, r, v;
Tree(const int L, const int R) : l(L), r(R), v(-1) {
if (l != r) {
int mid = (l + r) >> 1;
ls = new Tree(l, mid);
rs = new Tree(mid + 1, r);
}
}
Tree(Tree *pre, const int P, const int V) : l(pre->l), r(pre->r), v(0) {
if (l == r) {
v = V;
} else {
if (pre->ls->r >= P) {
rs = pre->rs;
ls = new Tree(pre->ls, P, V);
} else {
ls = pre->ls;
rs = new Tree(pre->rs, P, V);
}
}
}
int query(const int x) {
if (this->l == this->r) {
return this->v;
} else {
return (this->ls->r >= x) ? this->ls->query(x) : this->rs->query(x);
}
}
};
Tree *rot[maxn];
int tp, n, q, m;
int MU[maxn];
int main() {
qr(tp); qr(n); qr(q); qr(m);
rot[n] = new Tree(1, m);
for (int i = 1; i <= n; ++i) {
qr(MU[i]);
}
for (int i = n; i; --i) {
rot[i - 1] = new Tree(rot[i], MU[i], i);
}
for (int L, x, pos; q; --q) {
L = pos = 0; qr(L);
while ((L--) && (pos != -1)) {
x = 0; qr(x);
if ((pos = rot[pos]->query(x)) == -1) {
while (L--) {
qr(x);
}
break;
}
}
puts((~pos) ? "Yes" : "No");
}
return 0;
}
感謝
おかげで検査問題の人々 :@ ** _ Jiaoyue半分振りかける花** @ water_lift
この記事のレビューと校正に感謝:@ Dusker