1 条题解

  • 0
    @ 2025-8-24 22:21:44

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar a___
    这个家伙很蒻,什么也没有留下qwq

    搬运于2025-08-24 22:21:44,当前版本为作者最后更新于2021-04-08 17:03:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先,对于长序列号,建出它的 SAM。

    先考虑不能够完全匹配的情况。
    我们把短序列号在长序列号的 SAM 上匹配,前 ii 个字符匹配到的 SAM 上的节点 xx,根据 SAM 的性质,这前 ii 个字符组成的前缀串应为 xx 在 parent 树上的子树中任一(所有)节点对应串的后缀。也就是说,短串至少会在长串中 xx 对应子树中所有点的 pos 集合的并中的每一个位置匹配一次。
    另外,对于匹配不上的情况,出现了 nn 次。

    然后是能够完全匹配的情况。
    大体同上,不过有一点,匹配上了以后会停止匹配。也就是说,设停止位置为 pp,前 ii 个字符的前缀只在前述集合中在 [1,p(mi)][1,p-(m-i)] 中的位置匹配上过。
    另外,对于匹配不上的情况,出现了 pmp-m 次。

    所以问题转化为询问一个点的子树中权值小于等于一个数的权值的个数。于是我们直接 dsu on tree 维护询问即可。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    const int N=2e5+10,M=10,Q=3e6+10;
    int n,m,fa[N],to[N][M],len[N],pos[N],siz[N],son[N],cnt=1,las=1,a[Q],c[N];
    bool vis[N];
    long long ans[N];
    std::vector<int>g[N];
    std::vector<std::pair<int,int> >q[N];
    inline void update(int x,int a){for(;x<=n;x+=x&-x)c[x]+=a;}
    inline int query(int x){int a=0;for(;x;x-=x&-x)a+=c[x];return a;}
    void insert(int c,int i)
    {
    	int p=las,q=++cnt;las=q;
    	len[q]=len[p]+1;pos[q]=i;
    	while(p&&!to[p][c])to[p][c]=q,p=fa[p];
    	if(!p)fa[q]=1;
    	else
    	{
    		int x=to[p][c];
    		if(len[x]==len[p]+1)fa[q]=x;
    		else
    		{
    			int y=++cnt;memcpy(to[y],to[x],sizeof(to[x]));
    			fa[y]=fa[x];fa[x]=fa[q]=y;len[y]=len[p]+1;pos[y]=pos[x];
    			while(p&&to[p][c]==x)to[p][c]=y,p=fa[p];
    		}
    	}
    }
    inline int min(int a,int b){return a<b?a:b;}
    void dfs0(int u)
    {
    	siz[u]=1;
    	for(int i=0,l=g[u].size();i<l;i++)
    	{
    		dfs0(g[u][i]);
    		siz[u]+=siz[g[u][i]];
    		pos[u]=min(pos[u],pos[g[u][i]]);
    		if(siz[son[u]]<siz[g[u][i]])
    		son[u]=g[u][i];
    	}
    }
    int qwq,flg;
    void dfs1(int u)
    {
    	if(pos[u]&&flg==1&&!vis[pos[u]])update(pos[u],1),vis[pos[u]]=true;
    	if(pos[u]&&flg==-1&&vis[pos[u]])update(pos[u],-1),vis[pos[u]]=false;
    	for(int i=0,l=g[u].size();i<l;i++)
    	if(g[u][i]!=qwq)dfs1(g[u][i]);
    }
    void dfs(int u)
    {
    	for(int i=0,l=g[u].size();i<l;i++)
    	if(g[u][i]!=son[u])dfs(g[u][i]);
    	if(son[u])dfs(son[u]);
    	qwq=son[u],flg=1;dfs1(u);
    	for(int i=0,l=q[u].size();i<l;i++)
    	ans[q[u][i].second]+=query(q[u][i].first);
    	if(son[fa[u]]!=u)qwq=flg=-1,dfs1(u);
    }
    int main()
    {
    	int i,j,x,y;scanf("%d",&n);char ch;
    	for(i=1;i<=n;i++)scanf("%1d",&x),insert(x,i);
    	for(i=2;i<=cnt;i++)g[fa[i]].push_back(i);
    	dfs0(1);scanf("%d",&m);
    	for(i=1;i<=m;i++)
    	{
    		do ch=getchar(); while(ch<=32);a[0]=0;
    		do a[++a[0]]=ch-'0',ch=getchar(); while(ch>='0'&&ch<='9');
    		for(x=j=1;j<=a[0];j++)if(!to[x][a[j]])break;else x=to[x][a[j]];
    		if(j<=a[0])y=n+a[0];else y=pos[x];ans[i]=y-a[0];
    		for(x=j=1;j<=a[0];j++)if(!to[x][a[j]])break;else x=to[x][a[j]],q[x].push_back(std::make_pair(min(y-(a[0]-j),n),i));
    	}
    	dfs(1);
    	for(i=1;i<=m;i++)printf("%lld\n",ans[i]);
    	return 0;
    }
    
    • 1

    信息

    ID
    5490
    时间
    3000ms
    内存
    64MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者