! HAOI2018字串覆盖
Posted aurora2004
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了! HAOI2018字串覆盖相关的知识,希望对你有一定的参考价值。
心路历程
(r-l<51) 将两个字符串中间加入一个字符合并,做后缀数组,找到查询串的(rk)往前(min(hei)>=r)的串若为A串且贡献为正即可加入,对于每一个B的位置预处理,时间复杂度(O(nlog_n+(r-l)n+q))
(r-l>2000)后缀自动机+线段树合并,倍增找到点,跳endpos,跳的次数不会太多
SOL
数据有点特别啊~
(r-lin[51,2000])和>2000做法一样,因为数据随机分布,且不多
第一类数据的方法不用那么复杂,不过貌似我那个方法还做不出来
(f_{len,u,i})左起为u长度为len的字符串,接(2^i)个同样的字符串后下一个的左端点是多少,(g)表示权值是多少
用(hash)判重
(map<ull,queue<int>>q;) 真好用(放函数里(每次都新建一个,因为放全局会产生很多对映射,会TLE&MLE )我不会告诉你我交了20次才发现
ques
怎么找到(l-r)字符串的对应位置?
先预处理出b中每个前缀的最后一个字符的位置,和最大长度是多少,然后直接倍增跳link即可
细节好多┭┮﹏┭┮
#pragma GCC optimize(fast)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c==‘-‘)f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4;
struct node{
int len,link,nxt[26],cl;
}s[N<<1];
int siz,las;
inline void clear(){
siz=1;las=0;
s[0].len=0;
s[0].link=-1;
}
inline void extend(int c){
int cur=siz++,p;
s[cur].len=s[las].len+1;
for(p=las;p!=-1&&!s[p].nxt[c];p=s[p].link)
s[p].nxt[c]=cur;
if(p==-1){s[cur].link=0;las=cur;return;}
int q=s[p].nxt[c];
if(s[q].len==s[p].len+1){s[cur].link=q;las=cur;return;}
int clo=siz++;
s[clo]=s[q];
s[clo].len=s[p].len+1;
s[clo].cl=1;
for(;p!=-1&&s[p].nxt[c]==q;p=s[p].link)
s[p].nxt[c]=clo;
s[cur].link=s[q].link=clo;
las=cur;
}
#define lc ch[p][0]
#define rc ch[p][1]
int tot,ch[N*40][2],rt[N<<1];
void modify(int &p,int l,int r,int x){
if(!p)p=++tot;
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)modify(lc,l,mid,x);
else modify(rc,mid+1,r,x);
}
int merge(int x,int y){
if(!x||!y)return x|y;
int p=++tot;
lc=merge(ch[x][0],ch[y][0]);
rc=merge(ch[x][1],ch[y][1]);
return p;
}
int query(int p,int l,int r,int ql,int qr){
if(!p)return -1;
if(l==r)return l;
int mid=l+r>>1,ret=-1;
if(ql<=l&&r<=qr){
if(lc)return query(lc,l,mid,ql,qr);
else if(rc) return query(rc,mid+1,r,ql,qr);
}
if(ql<=mid)ret=query(lc,l,mid,ql,qr);
if(ret==-1&&mid<qr)ret=query(rc,mid+1,r,ql,qr);
return ret;
}
int n,k,ton[N],rk[N<<1],jump[N<<1][20],endpos[N],endlen[N];
char sa[N],sb[N];
inline void sam_init(){
clear();
for(int i=1;i<=n;i++)extend(sa[i]-‘a‘);
for(int i=1,p=0;i<siz;i++)
if(!s[i].cl)modify(rt[i],1,n,++p);
for(int i=1;i<siz;i++)ton[s[i].len]++;
for(int i=1;i<=n;i++)ton[i]+=ton[i-1];
for(int i=1;i<siz;i++)rk[ton[s[i].len]--]=i;
for(int i=siz-1;i;i--)
rt[s[rk[i]].link]=merge(rt[s[rk[i]].link],rt[rk[i]]);
for(int i=1;i<siz;i++)jump[i][0]=s[i].link;
for(int i=1;i<=18;i++)
for(int j=1;j<siz;j++)
jump[j][i]=jump[jump[j][i-1]][i-1];
for(int i=1,p=0,c,len=0;i<=n;i++){
c=sb[i]-‘a‘;
if(s[p].nxt[c]){len++;p=s[p].nxt[c];}
else{
while(p!=-1&&!s[p].nxt[c])p=s[p].link;
if(p==-1)p=len=0;
else{len=s[p].len+1;p=s[p].nxt[c];}
}
endpos[i]=p;endlen[i]=len;
}
}
inline int samrun(int x,int len){
if(endlen[x]<len)return -1;
x=endpos[x];
for(int i=18;i>=0;i--)
if(s[jump[x][i]].len>=len)x=jump[x][i];
return x;
}
#define ll long long
#define ull unsigned long long
ll ans[N],g[N][20];
int f[N][20];
struct ques{
int id,u,v,l;
};
vector<ques>qus[52];
ull mi[N],hsh[N];
inline void gethash(){
mi[0]=1;
for(int i=1;i<=n;i++){
mi[i]=mi[i-1]*131;
hsh[i]=hsh[i-1]+mi[i]*(sa[i]^48);
}
}
inline void solve(int len){
if(qus[len].empty())return;
map<ull,queue<int>>q;//放里面,因为外面会产生很多对映射,会TLE&MLE
for(int i=1;i<=n;i++){
static ull x;
for(int j=0;j<=18;j++)f[i][j]=0;
if(i+len>n)continue;
g[i][0]=k-i;
x=(hsh[i+len]-hsh[i-1])*mi[n-i-len];
while(!q[x].empty()&&q[x].front()<i-len){
f[q[x].front()][0]=i;
q[x].pop();
}
q[x].push(i);
}
for(int i=1;i<=18;i++)
for(int j=1;j<=n;j++){
f[j][i]=f[f[j][i-1]][i-1];
g[j][i]=g[j][i-1]+g[f[j][i-1]][i-1];
}
for(auto x:qus[len]){
static int p,w;
x.v=min(k-1,x.v-len);
if(x.u>x.v)continue;
p=samrun(x.l+len,len+1);
if(p==-1)continue;
w=query(rt[p],1,n,x.u+len,x.v+len);
if(w==-1)continue;
w-=len;
for(int i=18;i>=0;i--)
if(f[w][i]&&f[w][i]<=x.v){
ans[x.id]+=g[w][i];
w=f[w][i];
}
ans[x.id]+=g[w][0];
}
}
int main(){
n=read();k=read();
scanf("%s%s",sa+1,sb+1);
sam_init();
gethash();
int Q=read(),x,y,l,r,p,w;
for(int i=1;i<=Q;i++){
x=read();y=read();l=read();r=read();
if(r-l>50){
p=samrun(r,r-l+1);
if(p==-1)continue;
x+=r-l;y=min(n,min(k-1+r-l,y));
while(x<=y){
w=query(rt[p],1,n,x,y);
if(w==-1)break;
ans[i]+=k-w+r-l;
x=w+1+r-l;
}
}
else qus[r-l].push_back((ques){i,x,y,l});
}
for(int i=0;i<=50;i++)solve(i);
for(int i=1;i<=Q;i++)cout<<ans[i]<<"
";
return (0-0);
}
以上是关于! HAOI2018字串覆盖的主要内容,如果未能解决你的问题,请参考以下文章