題目鏈結。
雖然總長度我們不能確定,但是如果跟著第一行字串跑建 ac 自動機,節點數肯定 \(\le 10^5\) 的,因為每個字元最多增加乙個節點。
考慮乙個查詢 \((x, y)\), 即把字串 \(s[y]\) 的每個點對應在圖上的點 \(+1\),然後詢問 \(x\) 對應節點的子樹和。
子樹和想到 \(dfs\) 序差分 \(+\) 樹狀陣列
離線,把詢問 \(x\) 打進 \(d[y]\) 裡。 考慮對於每個 \(y\),先修改,然後詢問對應的 \(x\)。這裡的每個字串既是匹配串也是模式串,所以 \(s[y]\) 對應的節點就是一條從根出發的鏈。第二次再跟著輸入的第一行字串跑 \(ac\) 自動機,動態維護將根節點到當前節點上的所有點 \(+1\),遇到乙個 p 就停下來查詢即可。
注意 「b」 退回時,要刪除對應的影響。
\(o((n + m)logn)\)
#include #include #include #include using namespace std;
const int n = 100005;
typedef long long ll;
char s[n];
int n, m, cnt, dfncnt, fail[n], match[n], fa[n], c[n], tr[n][26];
int id[n], ans[n], dfn[n], sz[n], q[n], idx;
// bit
void add(int x, int k)
int ask(int x)
// 詢問 x 的子樹和
int query(int x)
// 詢問
struct q;
vectord[n]; // q[i] 表示插入恰好為 i 個字串需要的詢問
// fail 樹的邊
int head[n], nume = 0;
struct e e[n];
void addedge(int u, int v) ;
head[u] = nume;
}// ac 自動機:插入
void insert() }}
void dfs(int u)
}// 建 fail
void build() else tr[u][i] = tr[fail[u]][i];
} }for (int i = 1; i <= idx; i++) addedge(fail[i], i);
dfs(0);
}void work() else if (s[i] == 'p')
} else }}
int main() );
} insert();
build();
work();
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}
NOI2011阿狸的打字機
阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 l 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 這個字母加在凹槽的最後 l 按一下印有 b 的按鍵,打字機凹槽中最後乙個字母...
NOI2011 阿狸的打字機
阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有 26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 按 p 前凹槽中至少有乙個字母 按一下印有 b 的按鍵,打字機凹槽中最後乙個字...
NOI2011阿狸的打字機
剛學完字串演算法做一做題,這道題的質量的確很高,做完以後感覺對ac自動機有長進 一下的神仙思路來自yyb dalao 蒟蒻開始只想到了40分暴力,全程靠題解 step1 首先直接處理出所有的串再裸kmp好寫,但是覺得得分應該不高,也沒有人說能拿多少分 這個題正解的第一步是要想到ac自動機,準確地說和...