联考20200721 T2 s2mple


分析:
什么神仙题,考场上暴力都不会写
(深深地明白了自己是个废物的事实)
我们转换一下统计方式,假设要查询的串为\(P\),在前面加上一个串\(Q\),在后面加上一个串\(R\),得到的新串为\(T\),与前面的串Q形成一个二元组\((T,Q)\)
答案即为本质不同的二元组\((T,Q)\)个数,其中\(T\)\(S\)的子串
(感性理解一下发现很对(捂脸)
先统计\(Q+P\)的个数
构建一个SAM,答案即为fail树上\(P\)所在节点的后代的所有子串加上\(P\)所在节点集合长度不小于\(|P|\)的子串
所以该节点对权值的贡献可以表示为\(−|P|+b\),其中\(b\)是一个常数,我们可以事先处理出来。
\(P\)后面接\(R\)就是沿着SAM的边走,知道\(Q+P\)的数量后实际上是一个DP,一条边的起点会对终点做贡献,由于事先我们不知道\(Q+P\)的数量,但是由于其可以写成\(b-|P|\)的形式
那么某一个点的值会被写成\(k|P|+b\)的形式,我们沿着边维护每个点的\(k,b\)即可
转移时注意\(k|P|+b\)会变成\(k(|P|+1)+b=k|P|+(k+b)\)
每次询问找到|P|对应的节点,把|P|代进去算即可,这个可以在fail树上倍增找

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 1000005
#define INF 0x3f3f3f3f
#define MOD 998244353

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,Q;
char s[maxn];
struct node{
	int len,nxt[26],fa;
}t[maxn];
int lst=1,tot=1;
struct cp{
	long long b,k;
	cp(){}
	cp(long long x,long long y){b=x,k=y;}
	friend cp operator +(cp x,cp y){return cp(x.b+y.b,x.k+y.k);}
}f[maxn];
int d[maxn];
long long sz[maxn];
int F[maxn][20],pos[maxn];
inline bool cmp(int x,int y)
{return t[x].len<t[y].len;}

inline void ins(int c)
{
	int p=lst,np=lst=++tot;
	t[np].len=t[p].len+1;
	while(p&&!t[p].nxt[c])t[p].nxt[c]=np,p=t[p].fa;
	if(!p)t[np].fa=1;
	else
	{
		int q=t[p].nxt[c];
		if(t[q].len==t[p].len+1)t[np].fa=q;
		else
		{
			int nq=++tot;
			memcpy(t[nq].nxt,t[q].nxt,sizeof t[q].nxt);
			t[nq].fa=t[q].fa,t[nq].len=t[p].len+1;
			t[q].fa=t[np].fa=nq;
			while(p&&t[p].nxt[c]==q)t[p].nxt[c]=nq,p=t[p].fa;
		}
	}
}

inline int find(int x,int l)
{
	for(int i=19;~i;i--)if(F[x][i]&&t[F[x][i]].len>=l)x=F[x][i];
	return x;
}

int main()
{
	n=getint(),Q=getint();
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)ins(s[i]-97),pos[i]=lst;
	
	for(int i=1;i<=tot;i++)
	{
		d[i]=i;
		sz[i]=t[i].len-t[t[i].fa].len;
		if(t[i].fa)F[i][0]=t[i].fa;
	}
	
	for(int j=1;j<20;j++)for(int i=1;i<=tot;i++)
		F[i][j]=F[F[i][j-1]][j-1];
	sort(d+1,d+tot+1,cmp);
	for(int i=tot;i;i--)
	{
		int x=d[i];sz[t[x].fa]+=sz[x];
		f[x]=cp(sz[x]+t[t[x].fa].len+1,-1);
	}
	for(int i=tot;i;i--)
	{
		int x=d[i];
		for(int j=0;j<26;j++)if(t[x].nxt[j])
		{
			int v=t[x].nxt[j];
			f[x]=f[x]+cp(f[v].b+f[v].k,f[v].k);
		}
	}
	while(Q--)
	{
		int l=getint(),r=getint();
		int tmp=find(pos[r],r-l+1);
		printf("%lld\n",f[tmp].b+f[tmp].k*(r-l+1));
	}
}

posted @ 2020-07-22 18:22  Izayoi_Doyo  阅读(196)  评论(0编辑  收藏  举报