zoukankan      html  css  js  c++  java
  • BZOJ_3879_SvT_后缀数组+单调栈

    BZOJ_3879_SvT_后缀数组+单调栈

    Description

    (我并不想告诉你题目名字是什么鬼)

    有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].

    现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.

    Input

    第一行两个正整数n,m,分别表示S的长度以及询问的次数.

    接下来一行有一个字符串S.

    接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:

    首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.

    Output

    对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.
     

    Sample Input

    7 3
    popoqqq
    1 4
    2 3 5
    4 1 2 5 6

    Sample Output

    0
    0
    2


    类似http://www.cnblogs.com/suika/p/8995997.html这道题,只不过本题变成了给定多个后缀的LCP。

    先求出height数组,然后建立ST,设g[i]表示给出的第i个后缀到第i+1个后缀的LCP长度。

    转化为求所有区间最小值之和。

    dp[i]表示以第i个位置为结尾的所有区间最小值之和,对于i左边第一个大于等于g[i]的g[j],有f[i]=f[j]+(i-j)*g[i],答案就是dp[i]之和。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define RR register
    __attribute__((optimize("-O2")))inline char nc() {
    	static char buf[100000],*p1,*p2;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    __attribute__((optimize("-O2")))inline int rd() {
    	int x=0; RR char c=nc();
    	while(c<'0'||c>'9') c=nc();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=nc();
    	return x;
    }
    __attribute__((optimize("-O2")))inline int rc() {
    	char c=nc();
    	while(c<'a'||c>'z') c=nc();
    	return (int)c;
    }
    #define N 500050
    typedef long long ll;
    int n,m,wa[N],wb[N],wv[N],sa[N],height[N],rank[N],r[N],ws[N];
    char ch[N];
    int f[21][N],L[N],vis[N],s[N],g[N];
    int v[3000050],Q[3000050];
    ll dp[N];
    __attribute__((optimize("-O2")))void build_sa_array() {
    	m=27;
    	int i,j,p,*x=wa,*y=wb,*t;
    	for(i=0;i<m;i++) ws[i]=0;
    	for(i=0;i<n;i++) ws[x[i]=r[i]]++;
    	for(i=1;i<m;i++) ws[i]+=ws[i-1];
    	for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
    	for(p=j=1;p<n;j<<=1,m=p) {
    		for(p=0,i=n-j;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<n;i++) wv[i]=x[y[i]];
    		for(i=0;i<m;i++) ws[i]=0;
    		for(i=0;i<n;i++) ws[wv[i]]++;
    		for(i=1;i<m;i++) ws[i]+=ws[i-1];
    		for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
    		for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++) {
    			if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;
    			else x[sa[i]]=p++;
    		}
    	}
    	for(i=1;i<n;i++) rank[sa[i]]=i;
    	for(i=p=0;i<n-1;height[rank[i++]]=p)
    		for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
    }
    __attribute__((optimize("-O2")))int get_min(int l,int r) {
    	int len=L[r-l+1];
    	return min(f[len][l],f[len][r-(1<<len)+1]);
    }
    __attribute__((optimize("-O2")))void ST() {
    	int i,j;
    	for(i=2;i<=n;i++) L[i]=L[i>>1]+1;
    	for(i=1;i<=n;i++) f[0][i]=height[i];
    	for(i=1;(1<<i)<=n;i++) {
    		for(j=1;j+(1<<i)-1<=n;j++) {
    			f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
    		}
    	}
    }
    __attribute__((optimize("-O2")))bool cmp(int x,int y) {
    	return rank[x]<rank[y];
    }
    char pbuf[10000000] , *pp = pbuf;
    __attribute__((optimize("-O2")))void write(int x)
    {
        static int sta[35];
        int top = 0;
        if(!x)sta[++top]=0;
        while(x) sta[++top] = x % 10 , x /= 10;
        while(top) *pp ++ = sta[top -- ] ^ '0';
    }
    __attribute__((optimize("-O2")))int main() {
    	int T;
    	n=rd(); T=rd();
    	RR int i;
    	for(i=0;i<n;i++) r[i]=rc()-'a'+1;
    	r[n++]=0; 
    	int tot=0;
    	build_sa_array(); n--; ST();
    	while(T--) {
    		tot++;
    		int t=0;
    		v[0]=rd();
    		RR int j;
    		for(j=1;j<=v[0];j++) {
    			v[j]=rd();
    			v[j]--;
    			if(vis[v[j]]==tot) {
    				j--; v[0]--;
    			}
    			vis[v[j]]=tot;
    		}
    		sort(v+1,v+v[0]+1,cmp);
    		for(j=1;j<v[0];j++) {
    			g[j]=get_min(rank[v[j]]+1,rank[v[j+1]]);
    		}
    		t=1; Q[1]=0;
    		long long ans=0;
    		for(j=1;j<v[0];j++) {
    			while(t&&g[Q[t]]>g[j]) t--;
    			dp[j]=dp[Q[t]]+1ll*(j-Q[t])*g[j];
    			ans+=dp[j];
    			Q[++t]=j;
    		}
    		write(ans);*pp++='
    ';
    	}
    	fwrite(pbuf , 1 , pp - pbuf , stdout);
    }
    
  • 相关阅读:
    Java EE
    C++基础学习(二)之判断
    C++基础学习(一)之循环
    AutoCAD完全卸载
    point-cloud-annotation-tool编译发烧记_UBUNTU
    Ubuntu18.04安装QT5
    Ubuntu安装VTK-8.1
    常用Latex公式代码表[持续更新]
    shp矢量文件批处理裁剪栅格影像_IDL/ENVI
    摄影测量基本原理
  • 原文地址:https://www.cnblogs.com/suika/p/9078744.html
Copyright © 2011-2022 走看看