[Usaco10Dec] Threatening Letter G - 字尾自動機,貪心
阿新 • • 發佈:2020-07-11
Description
給你一個長度為 \(n\) 的串 \(s_1\),再給你一個長度為 \(m\) 的串 \(s_2\),問需要至少多少個 \(s_1\) 的子串才可以拼成 \(s_2\)?
Solution
對 \(s_1\) 建出 SAM,把 \(s_2\) 放到上面貪心地跑,如果能匹配就接著沿著 \(trans\) 邊走,不匹配則回到根結點,並且 \(ans+1\)
#include <bits/stdc++.h> using namespace std; const int N = 2000005; int ans=1; struct SAM { int len[N], ch[N][26], fa[N], ind, last; int t[N], a[N], cnt[N], f[N]; SAM() { ind = last = 1; } inline void extend(int id) { int cur = (++ ind), p; len[cur] = len[last] + 1; cnt[cur] = 1; for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur; if (!p) fa[cur] = 1; else { int q = ch[p][id]; if (len[q] == len[p] + 1) fa[cur] = q; else { int tmp = (++ ind); len[tmp] = len[p] + 1; for(int i=0;i<26;i++) ch[tmp][i] = ch[q][i]; fa[tmp] = fa[q]; for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp; fa[cur] = fa[q] = tmp; } } last = cur; } int p=1; void go(int id) { if(ch[p][id]) p=ch[p][id]; else p=ch[1][id], ++ans; } } sam; int main() { ios::sync_with_stdio(false); string str,tmp; int n,m; cin>>n>>m; while(str.length()<n) { cin>>tmp; str+=tmp; } for(int i=0;i<n;i++) sam.extend(str[i]-'A'); str=""; while(str.length()<m) { cin>>tmp; str+=tmp; } for(int i=0;i<m;i++) sam.go(str[i]-'A'); cout<<ans<<endl; }