NOI 2015品酒大会(后缀数组SA + 单调栈+RMQ求最大/小值)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/85697440

容易发现,我们只需要求出(最多r)相似(r=0~n-1)的对数,就可以用前缀和算出r相似的对数。
最多r相似的统计可以用后缀数组的h数组来统计。将每一对酒分类为r被h[2]卡住了,被h[3]卡住啦。。。。
那么就需要求出每一个h[i],最大的区间[a,b]使得 h [ i ] = m i n i = a b ( h [ i ] ) h[i] = min_{i=a}^b(h[i])
然后被i卡住的对数就是 ( i a ) ( b + 1 i ) (i-a) * (b+1-i) (h[i]的意义是sa[i]与sa[i-1]的最长公共前缀)
再RMQ预处理一下同样区间求最小值最大值就可以得到最大乘积了。

AC Code:

#include<bits/stdc++.h>
#define maxn 300005
#define LL long long
using namespace std;

int n;
LL cnt[maxn],Max[maxn];
int a[maxn],sa[maxn],rk[maxn],h[maxn],wa[maxn],wb[maxn],c[maxn],st[2][19][maxn],lg[maxn];
char s[maxn];
void Build(int n,int m)
{	int *x=wa,*y=wb,i,j,p,k=0;
	for(i=0;i<m;i++) c[i]=0;
	for(i=0;i<n;i++) c[x[i]=s[i]]++;
	for(i=1;i<m;i++) c[i]+=c[i-1];
	for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
	for(j=1,p=0;j<n && p<n;j<<=1,m=p)
	{	for(i=n-j,p=0;i<n;i++) y[p++]=i;
		for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
		for(i=0;i<m;i++) c[i]=0;
		for(i=0;i<n;i++) c[x[i]]++;
		for(i=1;i<m;i++) c[i]+=c[i-1];
		for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
		for(swap(x,y),i=1,p=1,x[sa[0]]=0;i<n;i++)
			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;}
	for(i=0;i<n;i++) rk[sa[i]]=i;
	for(i=0;i<n-1;h[rk[i++]]=k)
		for(k?k--:0;s[i+k]==s[sa[rk[i]-1]+k];k++);
	
}
inline int query_max(int a,int b)
{ 	int tmp = lg[b-a+1];
	return max(st[0][tmp][a],st[0][tmp][b-(1<<tmp)+1]);}
inline int query_min(int a,int b)
{ 	int tmp = lg[b-a+1];
	return min(st[1][tmp][a],st[1][tmp][b-(1<<tmp)+1]);}
deque<int>q;
int f[maxn];
int main()
{
	scanf("%d",&n);
	scanf("%s",s);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=2;i<=n;i++) lg[i] = lg[i>>1]+1;
	Build(n+1,200);
	for(int i=1;i<=n;i++) st[0][0][i] = st[1][0][i] = a[sa[i]+1];
	for(int j=1;j<19;j++)
		for(int i=1;i<=n;i++)
			if(i+(1<<j-1) <= n)
				st[0][j][i] = max(st[0][j-1][i],st[0][j-1][i+(1<<j-1)]),
				st[1][j][i] = min(st[1][j-1][i],st[1][j-1][i+(1<<j-1)]);
	memset(Max,-0x3f,sizeof Max);
	for(int i=2;i<=n+1;i++)
	{
		f[i]=i-1;
		for(;!q.empty() && h[q.back()]>=h[i];q.pop_back())
		{
			cnt[h[q.back()]] += 1ll * (q.back()-f[q.back()]) * (i - q.back());
			Max[h[q.back()]] = 
			max(Max[h[q.back()]] , 
			max(1ll * query_max(f[q.back()],q.back()-1)*query_max(q.back(),i-1),
			1ll * query_min(f[q.back()],q.back()-1)*query_min(q.back(),i-1))
			);
			f[i] = f[q.back()];
		}
		q.push_back(i);
	}
	
	
	for(int i=n;i>=0;i--) cnt[i]+=cnt[i+1] , Max[i] = max(Max[i],Max[i+1]);
	for(int i=0;i<n;i++) printf("%lld %lld\n",cnt[i],cnt[i]?Max[i]:0);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/85697440
今日推荐