結果
| 問題 |
No.430 文字列検索
|
| コンテスト | |
| ユーザー |
beet
|
| 提出日時 | 2018-11-10 18:49:23 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 25 ms / 2,000 ms |
| コード長 | 4,314 bytes |
| コンパイル時間 | 2,673 ms |
| コンパイル使用メモリ | 209,724 KB |
| 最終ジャッジ日時 | 2025-01-06 16:20:46 |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 14 |
ソースコード
#include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
struct SuffixArray{
int n;
string S;
vector<int> sa,lcp,rev;
SuffixArray(){}
SuffixArray(string &S):S(S){init();}
void init(){
n=S.length();
S.push_back('$');
build_sa();
build_lcp();
build_rmq();
}
void build_sa(){
sa.assign(n+1,0);
iota(sa.begin(),sa.end(),0);
sort(sa.begin(),sa.end(),
[&](int a,int b){
if(S[a]==S[b]) return a>b;
return S[a]<S[b];
});
vector<int> c(n+1,0),r(n+1),cnt(n+1),s(n+1);
for(int i=0;i<=n;i++) r[i]=S[i];
for(int len=1;len<=n;len*=2){
for(int i=0;i<=n;i++){
c[sa[i]]=
i>0 &&
r[sa[i-1]]==r[sa[i]] &&
sa[i-1]+len<=n &&
r[sa[i-1]+len/2]==r[sa[i]+len/2] ?
c[sa[i-1]]:i;
}
iota(cnt.begin(),cnt.end(),0);
copy(sa.begin(),sa.end(),r.begin());
for(int i=0;i<=n;i++){
int s1=r[i]-len;
if(s1>=0) sa[cnt[c[s1]]++]=s1;
}
c.swap(r);
}
}
bool lt_substr(string &T,int si=0,int ti=0){
int sn=S.size(),tn=T.size();
while(si<sn&&ti<tn){
if(S[si]<T[ti]) return 1;
if(S[si]>T[ti]) return 0;
si++;ti++;
}
return si>=sn&&ti<tn;
}
int lower_bound(string& T){
int low=0,high=n+1;
while(low+1<high){
int mid=(low+high)/2;
if(lt_substr(T,sa[mid],0)) low=mid;
else high=mid;
}
return high;
}
int upper_bound(string& T){
T.back()++;
int res=lower_bound(T);
T.back()--;
return res;
}
// O(|T|*log|S|)
int count(string& T){
return upper_bound(T)-lower_bound(T);
}
void build_lcp(){
lcp.assign(n,0);
rev.assign(n+1,0);
for(int i=0;i<=n;i++) rev[sa[i]]=i;
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[rev[i]-1];
if(h>0) h--;
for(;j+h<n&&i+h<n;h++){
if(S[j+h]!=S[i+h]) break;
}
lcp[rev[i]-1]=h;
}
}
int getlcp(int p,string &T,int d){
int i=0;
int len=min((int)T.length()-d,(int)S.length()-p-d);
while(i<len&&S[p+d+i]==T[d+i]) i++;
return i;
}
struct RMQ{
vector<vector<int> > dat;
vector<int> ht;
void init(int n){
int h=1;
while((1<<h)<n) h++;
dat.assign(h,vector<int>(n));
ht.assign(n+1,0);
for(int j=2;j<=n;j++) ht[j]=ht[j>>1]+1;
}
void build(int n,vector<int> &v){
int h=1;
while((1<<h)<n) h++;
for(int j=0;j<n;j++) dat[0][j]=v[j];
for(int i=1,p=1;i<h;i++,p<<=1)
for(int j=0;j<n;j++)
dat[i][j]=min(dat[i-1][j],dat[i-1][min(j+p,n-1)]);
};
int query(int a,int b){
if(a>b) swap(a,b);
int l=b-a;
return min(dat[ht[l]][a],dat[ht[l]][b-(1<<ht[l])]);
}
};
RMQ rmq;
void build_rmq(){
rmq.init(n);
rmq.build(n,lcp);
}
int lower_bound2(string &T){
int sl=S.length(),tl=T.length();
if(lt_substr(T,sa[sl-1],0)) return sl;
int p=tl;
int low=0,high=sl-1;
int l=getlcp(sa[low],T,0);
int r=getlcp(sa[high],T,0);
while(low+1<high){
int mid=(low+high)/2;
int k;
if(l>=r){
int m=rmq.query(low,mid);
if(m<l){
high=mid,r=m;
continue;
}
k=l+getlcp(sa[mid],T,l);
}else{
int m=rmq.query(mid,high);
if(m<r){
low=mid,l=m;
continue;
}
k=r+getlcp(sa[mid],T,r);
}
if(k==p) high=mid,r=k;
else if(S[sa[mid]+k]<T[k]) low=mid,l=k;
else high=mid,r=k;
}
return high;
}
int upper_bound2(string &T){
T.back()++;
int res=lower_bound2(T);
T.back()--;
return res;
}
// O(|T|+log|S|)
int count2(string& T){
return upper_bound2(T)-lower_bound2(T);
}
};
struct FastIO{
FastIO(){
cin.tie(0);
ios::sync_with_stdio(0);
}
}fastio_beet;
//INSERT ABOVE HERE
signed main(){
string s;
cin>>s;
int m;
cin>>m;
vector<string> c(m);
for(int i=0;i<m;i++) cin>>c[i];
SuffixArray sa(s);
Int cnt=0;
for(int i=0;i<m;i++) cnt+=sa.count2(c[i]);
cout<<cnt<<endl;
return 0;
}
beet