SP8093

前言

是通过另一道题来的,觉得这道题是神题就发题解了。

思路

这里我用的 SA 和莫队,我们首先可以得到一个很显然的性质,那就是对于两个串如果互相 \(A\)\(B\) 中出现过那么 \(lcp(A,B)=\min(|A|,|B|)\) 然后我们就可以将所有的模式串拼在一起做一遍 SA。

然后我们继续观察就能发现对于一个查询串,包含它的后缀一定是连续的一串,所以我们可以对于一个查询串在 \(rk\) 数组上求出是哪个区间(这里可以将左右端点分开求,可以二分出小于查询串中的最后一个作为 \(l\) 然后二分出小于等于查询串的最后一个作为 \(r\))。

那么我们就将问题转换为了:给你一个序列,再给你 \(m\) 次询问给你 \(l\)\(r\) 让你求出 \(l\sim r\) 中不同元素的数量。

这不是一眼莫队或者树状数组吗?其实有原题HH的项链

这里由于我不会 SA 所以用的二分和哈希,要比标算多一个 \(\log\)

代码

代码又臭又长

#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;i--)
#define fire signed
#define kong putchar(' ')
#define end putchar('\n')
#define in(x) scanf("%lld",&x)
#define lcm(x,y) x*y/__gcd(x,y)
#define il inline
il void print(int x) {
	if(x>=10) print(x/10);
	putchar(x%10+'0');
}
int n;
string s,t;
const int N=6e6+10,mod=998244353;
int f[N],jc[N];
int sa[N],l,m;
int get(int u,int r) {
	return (f[r]-f[u-1]*jc[r-u+1]%mod+mod)%mod;
}
bool cmp(int x,int y) {
	int L=0,r=min(l-x+1,l-y+1),res=0;
	while(L<=r) {
		int mid=L+r>>1;
		if(get(x,x+mid-1)==get(y,y+mid-1)) L=mid+1,res=mid;
		else r=mid-1;
	}
	return s[x+res]<s[y+res];
}
int len;
struct node{
	int l,r,id;
	friend bool operator<(const node&a,const node&b) {
		return a.l/len!=b.l/len?a.l<b.l:a.r<b.r;
	}
}q[N];
int cnt[N],id[N],ans,res[N],idx;
void pl(int x) {
	cnt[id[sa[x]]]++;
	if(cnt[id[sa[x]]]==1) ans++;
}
void jian(int x) {
	cnt[id[sa[x]]]--;
	if(cnt[id[sa[x]]]==false) ans--;
}
fire main() {
	in(n),in(m);
	char u='z'+1;
	s=" ";
	rep(i,1,n) {
		cin>>t;
		s+=t+'&';
		for(auto j:t) id[++l]=i;
		l++;
		id[l]=i;
	}
	jc[0]=1;
	rep(i,1,l) jc[i]=jc[i-1]*131%mod,f[i]=(f[i-1]*131%mod+s[i]-'a'+1)%mod,sa[i]=i;
	stable_sort(sa+1,sa+1+l,cmp);
	rep(i,1,m) {
		cin>>t;
		int lt=t.size();
		t=" "+t;
		int resl=1,resr=l;
		rep(j,1,lt) {
			int l=resl,r=resr,res=resl;
			while(l<=r) {
				int mid=l+r>>1;
				if(s[sa[mid]+j-1]<t[j]) l=mid+1,res=mid;
				else r=mid-1;
			}
			int lo=resl;
			resl=res+1;
			res=1;
			l=lo;
			r=resr;
			while(l<=r) {
				int mid=l+r>>1;
				if(s[sa[mid]+j-1]<=t[j]) l=mid+1,res=mid;
				else r=mid-1;
			}
			resr=r; 
		}
		if(resl<=resr) q[++idx]={resl,resr,i};
	}
	len=sqrt(idx);
	sort(q+1,q+1+idx);
	int l=1,r=0;
	rep(i,1,idx) {
		while(l<q[i].l) jian(l++);
		while(l>q[i].l) pl(--l);
		while(r<q[i].r) pl(++r);
		while(r>q[i].r) jian(r--);
		res[q[i].id]=ans;
	}
	rep(i,1,m) print(res[i]),end;
	return false;
}

posted @ 2024-01-31 11:36  highkj  阅读(6)  评论(0)    收藏  举报