Searching the String ZOJ - 3228 (AC自動機+思維98
阿新 • • 發佈:2020-08-25
可以重合的模式串,就是樸素的ac自動機。
對於第二種,相同模式串不能重合,我們可以知道,相同模式串有重合當且僅當第二次出現的位置-第一次出現的位置<字串長度,
我們可以開一個數組last[],last[i]記錄以i號節點結尾的單詞,最新匹配成功的位置 如在ababa中 ab第一次匹配的位置是 index=1 第二次 index=3 ,分別是2個b的下標,每次匹配到這個單詞,判斷一下 當前位置now-len>=last[i] 是的話就可以ans+1 .匹配過程基本上還是ac自動機中query函式的流程
void query(char *s)
{
int len=strlen(s),root=0;
for(int i=0;i<len;i++)
{
int u=tree[root][s[i]-'a'];
root=u;
while(u)
{
//ans[u][0]代表允許重合的情況,ans[u][1]代表不允許重回的情況,都算出來更簡潔
if(isstr[u]) ans[u][0]++;
//isstr[u]: u結尾的路徑是模式串的話,存單詞長度,否則是0
if(isstr[u] && i-last[u]>=isstr[u] )
{
ans[u][1]++;
last[u]=i;//更新u結尾的模式串,在文字串中最新出現的位置
}
u=fail[u];
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
具體細節見程式碼註釋
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<math.h>
#include<set>
using namespace std;
#define INF 1000000
#define LL unsigned long long
const int maxn=6e5+100;
int tot;//結點數 從1開始
int isstr[maxn];//結尾的長度
int tree[maxn][26];
int fail[maxn];
char s1[maxn];//文字串
int kinds[maxn/6];//第i個模式串的種類 可重合/不可
int ans[maxn][2];//節點最終的答案
int num[maxn/6];//每個單詞的尾節點編號
int last[maxn];//以其結尾的單詞上次匹配成功的位置
void Init()
{
memset(isstr,0,sizeof(isstr));
memset(fail,0,sizeof(fail));
memset(tree,0,sizeof(tree));
tot=0;
memset(ans,0,sizeof(ans));
memset(num,0,sizeof(num));
fill(last,last+maxn,-1);//初始化成-1 初始化成0的話abab裡面第一處ab就漏記了
}
int Insert(char* s)
{
int len=strlen(s);
int root=0;
for(register int i=0;i<len;i++)
{
int id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
isstr[root]=len;
return root