【bzoj 2434】【codevs 1946】[Noi2011]阿狸的打字机(AC自动机)
2434: [Noi2011]阿貍的打字機
Time Limit:?10 Sec??Memory Limit:?256 MBSubmit:?2477??Solved:?1382
[Submit][Status][Discuss]
Description
?阿貍喜歡收藏各種稀奇古怪的東西,最近他淘到一臺老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文字母和'B'、'P'兩個字母。
經阿貍研究發現,這個打字機是這樣工作的:
l 輸入小寫字母,打字機的一個凹槽中會加入這個字母(這個字母加在凹槽的最后)。
l 按一下印有'B'的按鍵,打字機凹槽中最后一個字母會消失。
l 按一下印有'P'的按鍵,打字機會在紙上打印出凹槽中現有的所有字母并換行,但凹槽中的字母不會消失。
例如,阿貍輸入aPaPBbP,紙上被打印的字符如下:
a
aa
ab
我們把紙上打印出來的字符串從1開始順序編號,一直到n。打字機有一個非常有趣的功能,在打字機中暗藏一個帶數字的小鍵盤,在小鍵盤上輸入兩個數(x,y)(其中1≤x,y≤n),打字機會顯示第x個打印的字符串在第y個打印的字符串中出現了多少次。
阿貍發現了這個功能以后很興奮,他想寫個程序完成同樣的功能,你能幫助他么?
Input
?輸入的第一行包含一個字符串,按阿貍的輸入順序給出所有阿貍輸入的字符。
第二行包含一個整數m,表示詢問個數。
接下來m行描述所有由小鍵盤輸入的詢問。其中第i行包含兩個整數x, y,表示第i個詢問為(x, y)。
Output
?輸出m行,其中第i行包含一個整數,表示第i個詢問的答案。
Sample Input
aPaPBbP3
1 2
1 3
2 3
Sample Output
21
0
HINT
?1<=N<=10^5
1<=M<=10^5
輸入總長<=10^5
Source
Trie
[Submit][Status][Discuss]【題解】【AC自動機+樹狀數組】
【首先將整個大串建trie樹(P、B不能算進去,遇到要特判,遇到P要將記錄每個單詞的數組更新;遇到B要記錄當前點的父節點,以備后面刪除時往回跳),再建fail樹,根據fail樹神奇的特性,將查詢自動機上root-y的每一個結點,沿著fail指針是否會走到x的結尾點,變為查詢自動機上root-y的所有結點中,有多少個在x的子樹中。按照fail樹跑一遍dfs序。 ?然后將詢問離線,按y排序,每次走到一個等于y的位置就查詢,用樹狀數組維護】
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s[100010]; struct question{int num,x,y; }ask[100010]; int nxt[100010][30],fail[100010],fa[100010],record[100010],num,sz; int a[200010],next[200010],p[100010],tot; int in[100010],out[100010],tp; int tree[200010],ans[100010]; int m,len,cnt;inline int tmp(question a,question b) {return a.y<b.y; } inline void add(int x,int y) {++tot; next[tot]=p[x]; a[tot]=y; p[x]=tot;++tot; next[tot]=p[y]; a[tot]=x; p[y]=tot; }void dfs(int now,int father) {in[now]=++tp;int u=p[now];while (u!=0){int v=a[u];if (v!=father) dfs(v,now);u=next[u];}out[now]=tp;return; }inline void trie() {int now=0;for (int i=0;i<len;++i){if (s[i]>='a'&&s[i]<='z'){int x=s[i]-'a';if (!nxt[now][x]) nxt[now][x]=++sz;fa[nxt[now][x]]=now;now=nxt[now][x];}if (s[i]=='P') record[++num]=now;if (s[i]=='B') now=fa[now];} } inline void make_fail() {queue<int>que;for (int i=0;i<26;++i)if (nxt[0][i]) add(0,nxt[0][i]),que.push(nxt[0][i]);while (!que.empty()){int now=que.front(); que.pop();for (int i=0;i<26;++i){int ch=nxt[now][i];if (!ch){nxt[now][i]=nxt[fail[now]][i]; continue;}int x=nxt[now][i];fail[x]=nxt[fail[now]][i];add(x,fail[x]);que.push(x);}} }inline void init(int x,int val) {for (int i=x;i<=tp;i+=i&(-i))tree[i]+=val; } inline int ask1(int x) {int sum=0;for (int i=x;i>=1;i-=i&(-i))sum+=tree[i];return sum; } int main() {int i,now,k;scanf("%s",s);len=strlen(s);trie();make_fail();dfs(0,-1);scanf("%d",&m);for (i=1;i<=m;++i)scanf("%d%d",&ask[i].x,&ask[i].y),ask[i].num=i;sort(ask+1,ask+m+1,tmp);now=0;k=1;for (i=0;i<len;++i){if (s[i]>='a'&&s[i]<='z'){int x=s[i]-'a';now=nxt[now][x];init(in[now],1);}if (s[i]=='B'){init(in[now],-1);now=fa[now];}if (s[i]=='P'){++cnt;if (cnt==ask[k].y)for (int j=k;ask[j].y==cnt;++j){int ans1=ask1(in[record[ask[j].x]]-1);int ans2=ask1(out[record[ask[j].x]]);ans[ask[j].num]=ans2-ans1;k=j+1;}}}for (i=1;i<=m;++i)printf("%d\n",ans[i]);return 0; }
轉載于:https://www.cnblogs.com/lris-searching/p/9402977.html
總結
以上是生活随笔為你收集整理的【bzoj 2434】【codevs 1946】[Noi2011]阿狸的打字机(AC自动机)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: url参数中有+、空格、=、%、、#等特
- 下一篇: windows64下安装MySQLdb连