好抽象啊,早上看了兩個多小時才看懂,\(\%\%\%fading\) 早就懂了
講解就算了吧……可以去看看其他人的部落格
\(siz\) 為該串出現的次數,\(l\) 為子串長度,每次乘一下就好了
\(code\ below:\)
#include #define ll long long
using namespace std;
const int maxn=2000000+10;
int n,a[maxn],c[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],siz[maxn];
char s[maxn];ll ans;
void insert(int c)
} siz[q]=1;
}int main()
printf("%lld\n",ans);
return 0;
}
題意簡述:\([tjoi2015]\) 弦論找第 \(k\) 小子串 \(t=0\) 的弱化版
直接像權值線段樹找第 \(k\) 小就好了
\(code\ below:\)
#include using namespace std;
const int maxn=200000+10;
int n,q,a[maxn],c[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],siz[maxn];
char s[maxn];
void insert(int c) }}
int main()
scanf("%d",&q);
int k,p;
while(q--)
else k-=siz[ch[p][i]];
}} putchar('\n');
} return 0;
}
\(t=1\) 的時候就是像模板一樣記錄一下 \(siz\),拓撲一遍
\(code\ below:\)
#include using namespace std;
const int maxn=1000000+10;
int n,q,t,a[maxn],c[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],siz[maxn],sum[maxn];
char s[maxn];
void insert(int c)
}siz[q]=1;
}int main()
siz[1]=0;
for(int i=cnt;i>=1;i--)
if(k>sum[1])
while(k)
else k-=sum[ch[p][i]];}}
putchar('\n');
return 0;
}
題意:找兩個串的最長公共子串
類似 \(kmp\) 一樣匹配兩個串,失配的話一直向上跳
\(code\ below:\)
#include using namespace std;
const int maxn=500000+10;
int n,a[maxn],c[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],ans;
char s[maxn];
void insert(int c) }}
int main()
ans=max(ans,len);
} printf("%d\n",ans);
return 0;
}
題意:找多個串的最長公共子串
類似雙串 \(lcs\) 一樣,就是在匹配的時候記錄下來長度,先取個 \(min\),再在 \(min\) 中取個 \(max\)
\(code\ below:\)
#include using namespace std;
const int maxn=200000+10;
int n,a[maxn],c[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],max[maxn],min[maxn],ans;
char s[maxn];
void insert(int c) }}
int main()
} for(int i=cnt;i>=1;i--)
} for(int i=2;i<=cnt;i++) ans=max(ans,min[i]);
printf("%d\n",ans);
return 0;
}
題意:問多少條本質不同路徑(可以翻轉)
邊搜邊建。因為葉子結點只有 \(20\) 個,每次就以度數為 \(1\) 的點開始搜尋,建乙個廣義字尾自動機。
#include #define ll long long
using namespace std;
const int maxn=200000+10;
int n,m,a[maxn],in[maxn],ch[maxn*20][26],fa[maxn*20],l[maxn*20],cnt;
int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;ll ans;
inline int read()
while(isdigit(ch))
return (f==1)?x:-x;
}inline void add(int x,int y)
int insert(int c,int p)
} return q;
}void dfs(int x,int f,int p)
}int main()
while(isdigit(ch))
return (f==1)?x:-x;
}void insert(int c) }}
void pushup(int now)
void update(int &now,int l,int r,int x)
int mid=(l+r)>>1;
if(x <= mid) update(l[now],l,mid,x);
else update(r[now],mid+1,r,x);
pushup(now);
}int merge(int x,int y,int l,int r)
int mid=(l+r)>>1,z=++tot;
l[z]=merge(l[x],l[y],l,mid);
r[z]=merge(r[x],r[y],mid+1,r);
pushup(z);
return z;
}int query(int now,int le,int ri,int l,int r)
int check(int len,int x,int l,int r)
int main()
for(int i=1;i<=cnt;i++) b[l[i]]++;
for(int i=1;i<=cnt;i++) b[i]+=b[i-1];
for(int i=1;i<=cnt;i++) a[b[l[i]]--]=i;
for(int i=cnt;i>=1;i--)
if(fa[a[i]]) t[fa[a[i]]]=merge(t[fa[a[i]]],t[a[i]],1,n);
for(int i=1;i<=cnt;i++) f[i][0]=fa[i];
for(int j=1;j<=20;j++)
for(int i=1;i<=cnt;i++) f[i][j]=f[f[i][j-1]][j-1];
int a,b,c,d,l,r,mid,ans;
while(m--)
printf("%d\n",ans);
} return 0;
}
題意:問兩個串的公共子串個數
如核心** \((l[i]-l[fa[i]])\times siz[i]\)
for(int i=2;i<=cnt;i++) sum[a[i]]=sum[fa[a[i]]]+(ll)(l[a[i]]-l[fa[a[i]]])*siz[a[i]];
scanf("%s",s+1);n=strlen(s+1);
int len=0,p=1,c;
for(int i=1;i<=cnt;i++)
}
\(code\ below:\)
#include #define ll long long
using namespace std;
const int maxn=400000+10;
int n,a[maxn],b[maxn],last,cnt,ch[maxn][26],fa[maxn],l[maxn],siz[maxn];
char s[maxn];ll sum[maxn],ans;
void insert(int c)
} siz[q]=1;
}int main()
} printf("%lld\n",ans);
return 0;
}
字尾自動機 SAM 學習筆記
參考資料 hihocoder1441 hihocoder1445 史上最通俗的字尾自動機詳解 練習題hihocoder1449 hihocoder1457 hihocoder1465 hihocoder1413 筆記 字串 aab 模板struct suffixautomaton int q ch ...
字尾自動機SAM
原理詳細的可以看史上最通俗的字尾自動機詳解 想看懂還是要花很久。實現 include include using namespace std const int maxn 2000010 struct node nodes maxn int las 1 tot 1 char st maxn void...
SAM 字尾自動機
好文 luogup3804 定義.對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。某一狀態t 0被稱作初始狀態,由它能夠到達其餘所有狀態。自動機中的所有轉移 即有向邊 都被某種符號...