BZOJ3277 串 和 BZOJ3473 字符串
阿新 • • 發佈:2019-05-07
sum can 問題 else red 復雜 javascrip rip val Problem 3473. -- 字符串
Submit: 1198 Solved: 547
[Submit][Status][Discuss]
abc
a
ab
[Submit][Status][Discuss] ?
HOME Back
DP出f[i]為i及其Parent祖先出現次數>=k有多少字符串(註意一個狀態貢獻的字符串為t[par].val-t[u].val),然後在跑一遍每個字符串得到答案就行了
字符串
3473: 字符串
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1198 Solved: 547
[Submit][Status][Discuss]
Description
給定n個字符串,詢問每個字符串有多少子串(不包括空串)是所有n個字符串中至少k個字符串的子串?Input
第一行兩個整數n,k。 接下來n行每行一個字符串。Output
一行n個整數,第i個整數表示第i個字符串的答案。Sample Input
3 1abc
a
ab
Sample Output
6 1 3HINT
對於 100% 的數據,1<=n,k<=10^5,所有字符串總長不超過10^5,字符串只包含小寫字母。
Source
Adera 1 杯冬令營模擬賽
HOME Back
分析
參照自為風月馬前卒和Candy?的題解。
廣義後綴自動機不就是把很多串的SAM建到了一個SAM上,建每個串的時候都從root開始(last=root)就行了........
廣義後綴自動機是Trie樹的後綴自動機,可以解決多主串問題
這樣的在線構造算法復雜度為O(G(T)),G(T)為Trie樹上所有葉子節點深度和,發現G(T)<=所有主串總長度
對於這題,首先我們要知道幾個定理
- 節點i表示的本質不同的字符串可以由len[i]?len[fa[i]]得到
- 一個串的子串 等價於 一個串所有前綴的所有後綴
這樣子串就轉換為求一個串的前綴的所有後綴的問題
前綴可以枚舉,問題轉換為求一個字符串的各個後綴在其他字符串中出現了多少次
這樣我們可以把廣義後綴自動機建出來,然後暴力沿著parent邊跑,這樣可以枚舉出所有後綴
同時為了不重復枚舉,我們需要記錄下每個後綴是否已經被枚舉過了
這樣最壞情況下復雜度為O(L^3/2),發生在n=L的時候(均值不等式啊)
這樣我們就可以知道一個狀態出現的次數是否>=K,接下來我們只要統計出這個狀態出現的次數就行了
然後就做完了。時間復雜度\(O(L^{1.5})\)
代碼
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
typedef long long ll;
using namespace std;
co int N=2e5;
string s[N];
int last=1,tot=1;
int ch[N][26],fa[N],len[N];
void extend(int c){
int p=last,cur=last=++tot;
len[cur]=len[p]+1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++tot;
memcpy(ch[clone],ch[q],sizeof ch[q]);
fa[clone]=fa[q],len[clone]=len[p]+1;
fa[cur]=fa[q]=clone;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
int vis[N],times[N],sum[N];
void dfs(int x){
if(x==1||vis[x]) return;
vis[x]=1;
dfs(fa[x]);
sum[x]+=sum[fa[x]];
}
int main(){
ios::sync_with_stdio(0);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;++i){
cin>>s[i];
last=1;
for(int j=0;j<s[i].length();++j) extend(s[i][j]-'a');
}
// GetTimes
for(int i=1;i<=n;++i){
int now=1;
for(int j=0;j<s[i].length();++j){
now=ch[now][s[i][j]-'a'];
for(int t=now;t&&vis[t]!=i;t=fa[t]) vis[t]=i,++times[t];
}
}
for(int i=1;i<=tot;++i) sum[i]=(times[i]>=k)*(len[i]-len[fa[i]]);
memset(vis,0,sizeof vis);
for(int i=1;i<=tot;++i) dfs(i);
for(int i=1;i<=n;++i){
int ans=0,now=1;
for(int j=0;j<s[i].length();++j)
now=ch[now][s[i][j]-'a'],ans+=sum[now];
printf("%d ",ans);
}
return 0;
}
BZOJ3277 串 和 BZOJ3473 字符串