• 【洛谷2178】[NOI2015] 品酒大会(后缀数组+单调栈)


    点此看题面

    大致题意: 给定一个字符串以及一个数组,定义(i,j(i<j))(k)相似的当且仅当后缀(i)和后缀(j)(LCP)长度大于等于(k)。对于每一个(k),求(k)相似的位置对数以及所有满足(k)相似的(i,j)(a_i imes a_j)的最大值。

    后缀数组

    一道比较水的题,感觉理解了后缀数组之后这种题其实一点都不难。

    看到(LCP),即便原本做这题的目的是为了写后缀自动机,我也会情不自禁地想要写后缀数组。。。

    在此题中,由于求解范围是整个数组,因此可以转化为:

    (i,j)(k)相似的,当且仅当(Height)数组上区间([i,j-1])的最小值大于等于(k)

    这里注意一点,如果我们先求出(LCP)恰好为(k)时的答案,最后从大到小扫一遍累计便可以求出(LCP)大于等于(k)的答案。

    然后就可以套路地单调栈。

    单调栈

    枚举(i),我们对于每一个以(i)为右端点时最小值相等的左端点区间,记录下这一最小值(k)、该区间的产生时间(p)、它的长度(l)、其中最大的(a)(Mx)、其中最小的(a)(Mn)

    为什么要记最小值?因为(a)可能小于(0),而两个负数相乘可以变回正数。

    区间的最小值显然满足单调性,因此只要维护一个单调栈使得左端点区间的(k)单调递增即可。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 300000
    #define LL long long
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,a[N+5];LL t1[N+5],t2[N+5];char s[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int f,T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0,f=1;W(!D) f=c^'-'?1:-1;W(x=(x<<3)+(x<<1)+(c&15),D);x*=f;}
    		I void reads(CI n,char *s) {W(isspace(c=tc()));for(RI i=1;i<=n;++i) s[i]=c,c=tc();}
    		Tp I void write(Ty x) {x<0&&(pc('-'),x=-x);W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void write(Con Ty& x,Con Ty& y) {write(x),pc(' '),write(y),pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class SuffixArray//后缀数组
    {
    	private:
    		int t[N+5],p[N+5],rk[N+5],SA[N+5],H[N+5];
    		I void Sort(CI S)
    		{
    			RI i;for(i=0;i<=S;++i) t[i]=0;for(i=1;i<=n;++i) ++t[rk[i]];
    			for(i=1;i<=S;++i) t[i]+=t[i-1];for(i=n;i;--i) SA[t[rk[p[i]]]--]=p[i];
    		}
    		I void GetSA()
    		{
    			RI i;for(i=1;i<=n;++i) rk[p[i]=i]=s[i];
    			RI k,t=0,S='z';for(Sort(S),k=1;t^n;k<<=1,S=t)
    			{
    				for(i=1;i<=k;++i) p[i]=n-k+i;for(t=k,i=1;i<=n;++i) SA[i]>k&&(p[++t]=SA[i]-k);
    				for(Sort(S),i=1;i<=n;++i) p[i]=rk[i];for(rk[SA[1]]=t=1,i=2;i<=n;++i)
    					(p[SA[i]]^p[SA[i-1]]||p[SA[i]+k]^p[SA[i-1]+k])&&++t,rk[SA[i]]=t;
    			}
    		}
    		I void GetH()
    		{
    			RI i,j,k=0;for(i=1;i<=n;++i) p[SA[i]]=i;for(i=1;i<=n;++i)
    			{
    				if(k&&--k,p[i]==1) continue;j=SA[p[i]-1];
    				W(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) ++k;H[p[i]]=k;
    			}
    		}
    	public:
    		I void Init() {GetSA(),GetH();}I int operator [] (CI x) Con {return H[x];}//返回Height数组
    		I int operator () (CI x) Con {return a[SA[x]];}//返回排名为x的位置的值
    }S;
    struct P
    {
    	int k,p,l,Mx,Mn;I P(CI t=0,CI i=0,CI s=0,CI f=-1e9,CI g=1e9):k(t),p(i),l(s),Mx(f),Mn(g){}
    	I void operator += (Con P& x) {l+=x.l,Gmax(Mx,x.Mx),Gmin(Mn,x.Mn);}//合并区间时,更新长度和极值
    }St[N+5];
    int main()
    {
    	RI i;for(F.read(n),F.reads(n,s),i=1;i<=n;++i) F.read(a[i]);
    	for(S.Init(),i=0;i<=n;++i) t2[i]=-1e18;RI T=0;P k;for(i=2;i<=n;++i)
    	{
    		k=P(S[i],i,1,S(i-1),S(i-1));W(T&&St[T].k>=k.k)//k初始化为当前位置信息
    			Gmax(t2[St[T].k],max(1LL*St[T].Mx*k.Mx,1LL*St[T].Mn*k.Mn)),//对于要删的区间,更新第二问
    			t1[St[T].k]+=1LL*(i-St[T].p)*St[T].l,k+=St[T--];St[++T]=k;//更新第一问,维护新区间信息
    	}
    	for(i=T;i;--i) t1[St[i].k]+=1LL*(n-St[i].p+1)*St[i].l;//对于栈中剩余元素求解第一问
    	for(St[T+1]=P(0,0,0,S(n),S(n)),i=T;i;--i) Gmax(t2[St[i].k],//注意往栈中加入第n个元素
    		max(1LL*St[i].Mx*St[i+1].Mx,1LL*St[i].Mn*St[i+1].Mn)),St[i]+=St[i+1];//对于栈中剩余元素求解第二问
    	for(i=n-2;~i;--i) t1[i]+=t1[i+1],Gmax(t2[i],t2[i+1]);//统计答案
    	for(i=0;i^n;++i) t1[i]?F.write(t1[i],t2[i]):F.write(0,0);return F.clear(),0;
    }
    
  • 相关阅读:
    SharePoint添加列表
    js求和
    经典.net面试题目
    sharepoint常见操作
    添加webpart时出现“此网页上的某个Web部件或Web表单控件无法显示或导入。该类型未注册为安全类型 。”
    关于js中"window.location.href"、"location.href"、"parent.location.href"、"top.location.href"的用法
    RegisterStartupScript,RegisterClientScriptBlock,Response.Write 简单说明区别
    jquery中的ready函数与window.onload谁先执行
    TreeView的TreeNode点击展示展开和收缩的效果
    如何让 TreeView 的节点不要生成 超级 链接
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2178.html
Copyright © 2020-2023  润新知