【题单——后缀数组】

P4051 [JSOI2007]字符加密


字符串翻倍,最后输出sa[]对应后缀最后一位

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
char s[N];
int sa[N],rk[N],tp[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	for(int i=1;i<=n;++i)rk[i]=s[i],tp[i]=i;
	Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);m=1005;
	for(int i=n+1;i<=n*2;i++)s[i]=s[i-n];
	n<<=1;
	SA();
	n>>=1;
	for(int i=1;i<=n<<1;i++)
	if(sa[i]<=n)printf("%c",s[sa[i]+n-1]);
}

P2870 [USACO07DEC]Best Cow Line G


两头指针贪心,如果遇见相同的就顿一下
在后面插一个反串,就可以比较两头指针了
(仔细想一下,可以知道后面多余的不会有影响)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m;
char fw[N],s[N],ans[N];
void pr()
{
	for(int i=1;i<=n;i++)
	{
		printf("%c",ans[i]);
		if(i%80==0)printf("\n");
	}
}
int sa[N],tp[N],rk[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	for(int i=1;i<=n;i++)rk[i]=s[i]-'A'+1,tp[i]=i;
	m=30;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
void work()
{
	int l=1,r=n,p=0;
	while(l<r)
	{
		if(s[l]==s[r])
		{
			if(rk[l]<rk[2*n-r+1])ans[++p]=s[l++];
			else		 	     ans[++p]=s[r--];
		}
		else
		{
			if(s[l]<s[r])ans[++p]=s[l++];
			else		 ans[++p]=s[r--];
		}
	}ans[++p]=s[l];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",fw);
		s[i]=s[2*n-i+1]=fw[0];
	}
	n<<=1;SA();n>>=1;
	work();pr();
}

P2852 [USACO06DEC]Milk Patterns G


找一段 k k k长的 h e i g h t height height最小值的最大值
单调队列

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10;
int n,m=1,k;
int a[N];
struct qus{
	int num,id;
	bool operator<(const qus a)const{return num<a.num;}
}bt[N];
void ls()
{
	sort(bt+1,bt+n+1);
	for(int i=1;i<=n;i++)
	{
		if(bt[i].num!=bt[i-1].num)m++;
		a[bt[i].id]=m;
	}
}
int tp[N],rk[N],sa[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	for(int i=1;i<=n;i++)rk[i]=a[i],tp[i]=i;
	Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];//排名i与排名i-1(lcp )
void get_ht()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++;
		h[rk[i]]=k;
	}
}
int z[N],p1,p2;
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&bt[i].num);
		bt[i].id=i;
	}
	ls();SA();get_ht();
	int ans=0;p1=1,p2=0;
	for(int i=1;i<=n;i++)
	{
		while(p1<=p2&i-z[p1]+1>=k)p1++;
		while(p1<=p2&&h[z[p2]]>=h[i])p2--;
		z[++p2]=i;
		if(i>=k)ans=max(ans,h[z[p1]]);
	}
	printf("%d",ans);
}

P4248 [AHOI2013]差异


求所有 h e i g h t height height区间最小值之和
分别找到单调栈的左右最大区间,累加

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
int n,m;
char s[N];
int tp[N],sa[N],rk[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;
	Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_ht()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
int z[N],p;
int L[N],R[N];
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);m=30;
	SA();get_ht();
	z[p=1]=1;
	for(int i=2;i<=n;i++)
	{
		while(p&&h[z[p]]>h[i])R[z[p--]]=i;
		L[i]=z[p];z[++p]=i;
	}while(p)R[z[p--]]=n+1;
	ll ans=(ll)n*(n-1)*(n+1)/2;
	for(int i=2;i<=n;i++)
	ans-=2ll*(R[i]-i)*(i-L[i])*h[i];
	printf("%lld",ans);
}

SP705 SUBST1 - New Distinct Substrings


本质不同的子串个数,即 n ( n + 1 ) 2 − ∑ h e i g h t i \frac{n(n+1)}2-\sum_{height_i} 2n(n+1)heighti

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
char s[500005];
int tp[500005],sa[500005],rk[500005],t[500005];
void Qsort()
{
	for(int i=0;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	m=1000;
	for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[100005];
void get_h()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
signed main()
{
	int T;cin>>T;
	while(T--)
	{
		scanf("%s",s+1);
		n=strlen(s+1);
		SA();get_h();
		int ans=n*(n+1)/2;
		for(int i=1;i<=n;i++)ans-=h[i];
		cout<<ans<<endl;
	}
}

P3181 [HAOI2016]找相同字符


两串拼接的本质不同子串个数 − - 两个串分别的本质不同子串个数

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e5+10;
int n,m;
int tp[N],rk[N],sa[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA(char *s)
{
	for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_h(char *s)
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
int z[N],p;
int L[N],R[N];
ll work(char *s,int len)
{
	n=len;m=30;
	SA(s);get_h(s);
	z[++p]=1;
	for(int i=2;i<=n;i++)
	{
		while(p&&h[z[p]]>h[i])R[z[p--]]=i;
		L[i]=z[p];z[++p]=i;
	}while(p)R[z[p--]]=n+1;
	ll ans=0;
	for(int i=1;i<=n;i++)ans+=(ll)(R[i]-i)*(i-L[i])*h[i];
	return ans;
}
ll ans=0;
int l1,l2;
char s1[N],s2[N];
int main()
{
	scanf("%s%s",s1+1,s2+1);
	l1=strlen(s1+1);ans-=work(s1,l1);
	l2=strlen(s2+1);ans-=work(s2,l2);
	for(int i=1;i<=l2;i++)s1[l1+i+1]=s2[i];s1[l1+1]='z'+1;
	ans+=work(s1,l1+l2+1);
	printf("%lld",ans);
}

SP1811 LCS - Longest Common Substring


思考一下,只要相邻两个 h e i g h t height height来自不同串,就更新答案

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m;
char s[N];
int tp[N],sa[N],rk[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	m=1000;
	for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
	Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(rk,tp);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_h()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
int l1,l2;
char s1[N],s2[N];
int z[N],p;
int work()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if((sa[i]<=l1&&sa[i-1]>l1+1)||(sa[i-1]<=l1&&sa[i]>l1+1))
		ans=max(ans,h[i]);
	}return ans;
}
int main()
{
	scanf("%s%s",s1+1,s2+1);
	l1=strlen(s1+1),l2=strlen(s2+1);
	n=l1+l2+1;
	for(int i=1;i<=l1;i++)s[i]=s1[i];s1[l1+1]='z'+1;
	for(int i=1;i<=l2;i++)s[i+l1+1]=s2[i];
	SA();get_h();
	printf("%d",work());
}

P5341 [TJOI2019]甲苯先生和大中锋的字符串


注意:好K次
找到一段连续恰好K长 [ L , R ] [L,R] [L,R],且 h e i g h t L − 1 < m i n n 且 h e i g h t R + 1 < m i n n height_{L-1}<minn且height_{R+1}<minn heightL1<minnheightR+1<minn说明我们可以找到 [ m a x ( h e i g h t L − 1 , h e i g h t R + 1 ) + 1 , m i n n ] [max(height_{L-1},height_{R+1})+1,minn] [max(heightL1,heightR+1)+1,minn]的恰好子串,差分即可

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m,k;
char s[N];
int tp[N],rk[N],sa[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	m=30;
	for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_h()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}h[n+1]=0;//因为后面要用i+1,所以千万要清零!!!(一页的WA教你做人)
}
int a[N];
int z[N],p1,p2;
int work()
{
	p1=1,p2=0;
	for(int i=1;i<=n;i++)
	{
		while(p1<=p2&&i-z[p1]+1>k-1)p1++;
		while(p1<=p2&&h[z[p2]]>h[i])p2--;
		z[++p2]=i;
		if(k!=1)
		{
			if(i>=k&&h[i-k+1]<h[z[p1]]&&h[i+1]<h[z[p1]])
			{
				a[max(h[i-k+1],h[i+1])+1]++;
				a[h[z[p1]]+1]--;
			}			
		}
		else
		{
			if(i>=k&&h[i-k+1]<n-sa[i]+1&&h[i+1]<n-sa[i]+1)
			{
				a[max(h[i-k+1],h[i+1])+1]++;
				a[n-sa[i]+2]--;
			}	
		}
	}
	int tmp=0,bj=-1,maxx=0;
	for(int i=1;i<=n;i++)
	{
		tmp+=a[i];a[i]=0;
		if(tmp&&tmp>=maxx)maxx=tmp,bj=i;
	}
	return bj;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s%d",s+1,&k);
		n=strlen(s+1);
		SA();get_h();
		printf("%d\n",work());
	}
}

P2463 [SDOI2008]Sandy的卡片


将数字串差分处理(记得小心负数),多个串拼接中间要加未出现的字符
二分答案,查是否一段连续的区间 h e i g h t i ≥ m i d height_i\geq mid heightimid,且来自 T T T个字符串

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m;
int bl[N];
int s[N];
int t[N],tp[N],sa[N],rk[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	m=10000;
	for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_h()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
int T;
bool vis[N];
int z[N],p;
#define bl(x) bl[sa[x]]
bool check(int mid)
{
	while(p)vis[z[p--]]=0;
	for(int i=1;i<=n;i++)
	{
		if(h[i]<mid){while(p)vis[z[p--]]=0;}
		if(!vis[bl(i)])
		{
			vis[bl(i)]=1;z[++p]=bl(i);
			if(p==T)return 1;
		}
	}
	return 0;
}
int fw[N];
int main()
{
	scanf("%d",&T);
	for(int len,i=1;i<=T;i++)
	{
		scanf("%d",&len);
		for(int j=1;j<=len;j++)scanf("%d",&fw[j]);
		for(int j=2;j<=len;j++)s[++n]=(fw[j]-fw[j-1])+2000,bl[n]=i;
		s[++n]=5000;
	}
	SA();get_h();
	int l=1,r=n,ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))l=mid+1,ans=mid;
		else		  r=mid-1;
	}
	printf("%d",ans+1);
}

P2178 [NOI2015]品酒大会


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
const ll INF=1e18+10;
int n,m;
char s[N];
int tp[N],rk[N],sa[N],t[N];
void Qsort()
{
	for(int i=1;i<=m;i++)t[i]=0;
	for(int i=1;i<=n;i++)t[rk[i]]++;
	for(int i=1;i<=m;i++)t[i]+=t[i-1];
	for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
	for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;m=30;Qsort();
	for(int w=1,p;w<=n;m=p,w<<=1)
	{
		p=0;
		for(int i=n-w+1;i<=n;i++)tp[++p]=i;
		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
		Qsort();swap(tp,rk);p=rk[sa[1]]=1;
		for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
		if(p==n)return ;
	}
}
int h[N];
void get_h()
{
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1)continue;
		int j=sa[rk[i]-1];if(k)k--;
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
	}
}
ll a[N];
ll ans1[N],ans2[N];
int z[N],p;
ll minn[N],maxx[N];
int L[N],R[N];
void work()
{
	ll ma=-INF,mi=INF;
	for(int i=1;i<=n;i++)ans2[i]=LLONG_MIN;
	z[++p]=1;
	for(int i=2;i<=n;i++)
	{
		ma=mi=a[sa[i-1]];
		while(p&&h[z[p]]>h[i])
		{
			ans2[h[z[p]]]=max(ans2[h[z[p]]],max(1ll*maxx[p]*ma,1ll*minn[p]*mi));
			ma=max(ma,maxx[p]);mi=min(mi,minn[p]);
			R[z[p--]]=i;
		}
		L[i]=z[p];
		z[++p]=i;minn[p]=mi,maxx[p]=ma;
	}
	ma=mi=a[sa[n]];
	while(p)
	{
		ans2[h[z[p]]]=max(ans2[h[z[p]]],max(1ll*maxx[p]*ma,1ll*minn[p]*mi));
		ma=max(ma,maxx[p]);mi=min(mi,minn[p]);
		R[z[p--]]=n+1;
	}
	for(int i=2;i<=n;i++)ans1[h[i]]+=(ll)(R[i]-i)*(i-L[i]);
	for(int i=n-2;i>=0;i--)
	{
		ans1[i]+=ans1[i+1];
		ans2[i]=max(ans2[i],ans2[i+1]);
	}
}
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	SA();get_h();
	work();
	for(int i=0;i<n;i++)
	{
		printf("%lld %lld\n",ans1[i],ans1[i]==0?0:ans2[i]);
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值