您的位置:首页 > 其它

[后缀自动机 阈值] LOJ#6031. 「雅礼集训 2017 Day1」字符串

2018-01-24 14:05 495 查看
对 k 阈值

如果 k≤S

枚举询问串的每个子串,在后缀自动机上找到对应的节点就可以了

O(qkk2logn)

如果 k>S

枚举询问串的前缀,找到对应节点,每个和这个前缀相关的询问是这个前缀的后缀,在fail树上倍增

O(qk(k+mlogn))

这个log我卡不掉,只能对着数据卡常了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <map>

using namespace std;

typedef long long ll;

const int N=200010;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void read(char *a){
char c=nc(); int x=0;
for(;c>'z'||c<'a';c=nc());for(;c>='a'&&c<='z';a[++x]=c,c=nc());
}

int n,m,q,k,S,l
,r
;
char s
;

int p=1,cnt=1,nxt
[30],fail
,len
,val
;

inline void extend(int c){
int np=++cnt; len[np]=len[p]+1; val[np]=1;
while(p && !nxt[p][c]) nxt[p][c]=np,p=fail[p];
if(!p) fail[np]=1;
else{
int q=nxt[p][c];
if(len[q]==len[p]+1) fail[np]=q;
else{
int nq=++cnt; len[nq]=len[p]+1;
memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
fail[nq]=fail[q];
fail[q]=fail[np]=nq;
while(p && nxt[p][c]==q) nxt[p][c]=nq,p=fail[p];
}
}
p=np;
}

int id
,t
,fa
[20];

inline void Pre(){
for(int i=1;i<=cnt;i++) t[len[i]]++;
for(int i=1;i<=cnt;i++) t[i]+=t[i-1];
for(int i=1;i<=cnt;i++) id[t[len[i]]--]=i;
for(int i=cnt;i;i--)
val[fail[id[i]]]+=val[id[i]];
for(int i=1;i<=cnt;i++){
int x=id[i]; fa[x][0]=fail[x];
for(int j=1;j<=10;j++) fa[x][j]=fa[fa[x][j-1]][j-1];
}
}

const int MAX=316*320+320;

int ans
;
vector<int> M[MAX];
int ap[MAX],flg[MAX],pr[320][N>>1];

inline int calc(pair<int,int> A,int L,int R){
int g=A.first*320+A.second;
if(flg[g]){
int cur=flg[g];
return pr[cur][R]-pr[cur][L-1];
}
vector<int> c=M[A.first*320+A.second];
return upper_bound(c.begin(),c.end(),R)-lower_bound(c.begin(),c.end(),L);
}

void PutAns(ll x){
if(x>=10) PutAns(x/10); putchar(x%10+'0');
}

inline void Case1(){
for(int i=1;i<=m;i++) ap[l[i]*320+r[i]]++;
int S=316,cc=0;
for(int l=1;l<=k;l++)
for(int r=l;r<=k;r++)
if(ap[l*320+r]>S){
flg[l*320+r]=++cc;
for(int i=1;i<=m;i++)
pr[cc][i]=pr[cc][i-1]+(::l[i]==l && ::r[i]==r);
}
for(int i=1;i<=m;i++) M[l[i]*320+r[i]].push_back(i);
while(q--){
int L,R;
read(s); read(L); read(R);
L++; R++;
ll ans=0;
for(int l=1;l<=k;l++){
int cur=1;
for(int r=l;r<=k;r++){
if(!nxt[cur][s[r]-'a']) break;
cur=nxt[cur][s[r]-'a'];
ans+=val[cur]*calc(make_pair(l,r),L,R);
}
}
PutAns(ans); putchar('\n');
}
}

vector<pair<int,int> > Q
;

inline void Case2(){
for(int i=1;i<=m;i++) Q[r[i]].push_back(make_pair(l[i],i));
while(q--){
read(s);
int L,R; read(L); read(R);
L++; R++;
int cur=1,cnt=0; ll ans=0;
for(int r=1;r<=k;r++){
while(cur && !nxt[cur][s[r]-'a'])
cur=fail[cur],cnt=len[cur];
if(!cur){
cur=1; cnt=0; continue;
}
cur=nxt[cur][s[r]-'a']; cnt++;
for(auto u : Q[r]){
int l=u.first,t=u.second;
if(r-l+1>cnt || t<L || t>R) continue;
int c=cur;
for(int i=10;~i;i--)
if(len[fa[c][i]]>=r-l+1) c=fa[c][i];
ans+=val[c];
}
}
PutAns(ans); putchar('\n');
}
}

int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
read(n); read(m); read(q); read(k);
read(s);
for(int i=1;i<=n;i++) extend(s[i]-'a');
Pre();
for(int i=1;i<=m;i++)
read(l[i]),read(r[i]),l[i]++,r[i]++;
k<=310?Case1():Case2();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: