• Codeforces 1073G Yet Another LCP Problem $SA$+单调栈


    题意

    给出一个字符串(s)(q)个询问。
    每次询问给出两个长度分别为(k,l)的序列(a)和序列(b)
    (sum_{i=1}^{k}sum_{j=1}^{l}lcp(s[a_i…n],s[b_j…n]))

    Solution

    (SA)练习题。
    求出(height)数组后,每次询问相当于询问(l*k)个区间(min)之和。
    岂不单调栈?
    对没错,这个题解就是提供给你代码对拍的

    #include<bits/stdc++.h>
    #define For(i,x,y) for (register int i=(x);i<=(y);i++)
    #define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
    #define cross(i,k) for (register int i=first[k];i;i=last[i])
    using namespace std;
    typedef long long ll;
    inline ll read(){
        ll x=0;int ch=getchar(),f=1;
        while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
        if (ch=='-'){f=-1;ch=getchar();}
        while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N = 2e5+10;
    int n,Q,l[N],k[N];
    char s[N];
    int SA[N],height[N],rk[N],cnt[N],x[N],y[N];
    inline void RadixSort(){
    	int Max=0;
    	For(i,1,n) cnt[x[i]]++,Max=max(Max,x[i]);
    	For(i,1,Max) cnt[i]+=cnt[i-1];
        Dow(i,n,1) SA[cnt[x[y[i]]]--]=y[i];
    	For(i,1,Max) cnt[i]=0;
    }
    inline void GetSA(){
    	For(i,1,n) x[i]=s[i],y[i]=i;
    	RadixSort();
    	for (int i=1,p;p<n;i<<=1){
    		p=0;
    		For(j,n-i+1,n) y[++p]=j;
    		For(j,1,n) if (SA[j]>i) y[++p]=SA[j]-i;
    		RadixSort(),swap(x,y),x[SA[1]]=p=1;
    		For(j,2,n) x[SA[j]]=(y[SA[j]]==y[SA[j-1]]&&y[SA[j]+i]==y[SA[j-1]+i])?p:++p;
    	}
    	For(i,1,n) rk[SA[i]]=i;
    	int now=0;
    	For(i,1,n){
    		if (rk[i]==1) continue;now=max(now-1,0);
            for (int j=SA[rk[i]-1];j+now<=n&&i+now<=n&&s[j+now]==s[i+now];now++);
    		height[rk[i]]=now; 
    	}
    }
    int Min[N][20],Log[N];
    inline void init(){
    	For(i,1,n) Log[i]=log(i)/log(2);
    	For(i,1,n) Min[i][0]=height[i];
    	For(j,1,Log[n]) For(i,1,n-(1<<j)+1) Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
    }
    inline int Query(int l,int r){
    	int L=Log[r-l+1];
    	return min(Min[l][L],Min[r-(1<<L)+1][L]);
    }
    struct node{
    	int x,y;
    }a[N<<1];
    inline bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    int top,q[N<<1],c[N<<1];
    ll Sum,ans;
    inline void solve(int m,int M){
    	int cnt=0;
    	For(i,1,M) a[++cnt]=(node){rk[read()],1};
    	For(i,1,m) a[++cnt]=(node){rk[read()],0};
    	sort(a+1,a+1+cnt,cmp),ans=top=Sum=0;
    	a[cnt+1]=(node){-1,0};
    	int r=cnt;while (a[r].y==1) r--;
    	Dow(i,r,1){
    		if (i!=r){
    			int x=Query(a[i].x+1,a[i+1].x),s=a[i+1].y^1;
    			while (x<=q[top]&&top) Sum-=c[top]*q[top],s+=c[top--];
    			q[++top]=x,c[top]=s,Sum+=1ll*s*x;
    		}
    		if (a[i].y) ans+=Sum;
    		else if (a[i+1].x==a[i].x) ans+=n-SA[a[i].x]+1;
    	}
    	For(i,2,cnt) if (a[i].x==a[i-1].x) swap(a[i],a[i-1]);
    	top=Sum=0;
    	r=1;while (a[r].y==1) r++;
    	For(i,r,cnt){
    		if (i!=r){
    			int x=Query(a[i-1].x+1,a[i].x),s=a[i-1].y^1;
    			while (x<=q[top]&&top) Sum-=c[top]*q[top],s+=c[top--];
    			q[++top]=x,c[top]=s,Sum+=1ll*s*x;
    		}
    		if (a[i].y) ans+=Sum;
    	}
    }
    ll Ans[N];
    int main(){
    	n=read(),Q=read(),scanf("%s",s+1);
    	GetSA(),init();
    	For(i,1,Q) solve(read(),read()),Ans[i]=ans;
    	For(i,1,Q) printf("%lld
    ",Ans[i]);
    }
    
  • 相关阅读:
    JavaScript基础概念之----作用域
    Vue-Router基础知识点总结【vue系列】
    前端如何进行seo优化
    常见算法
    ES6新特性
    VUE内使用AES(BCB)加解密
    VUE内使用RSA加解密
    vue 使用v-html指令渲染的富文本无法修改样式的解决方法
    js中字符串可以调用的方法
    基于H5的混合开发介绍(一)WebView
  • 原文地址:https://www.cnblogs.com/zykykyk/p/10121054.html
Copyright © 2020-2023  润新知