zoukankan      html  css  js  c++  java
  • BZOJ3172 [Tjoi2013]单词 字符串 SA ST表

    原文链接http://www.cnblogs.com/zhouzhendong/p/9026543.html

    题目传送门 - BZOJ3172

    题意

      输入$n(nleq 200)$个字符串,保证长度总和$leq 10^6$。

      对于每一个字符串,求它在所有的$n$个字符串(包括它自己)中出现了几次。(同一个字符串内可能出现多次当前的字符串)

    题解

      听百度说这题可以用AC自动机??

      然而我顺手大力$SA$干掉了此题。

      本题用$SA$做好像很容易。

     

      首先,把输入的字符串连接成一个字符串,不同的单词之间用特殊字符隔开。注意最终串长度是$1e6+n$级别的,数组别开小。

      然后闭着眼睛$SA$啊。

      记第$i$个串的开头为$p_i$,长度为$len_i$。

      对于第$i$个串,就是从$rank_{p_i}$位置开始。向左,利用$height$表示的$lcp$长度,如果$lcp$长度不小于$len_i$,那么仍然可以继续向左扩张。向右同理。

      这样好像就可以过掉了。

      然而我却在搜百度前就写完了$ST$表……好像快了不少。

      上一句为题外话。

      向左向右一步一步扩张显然太慢,所以我们预处理$height$的$ST$表,然后倍增地走。每次走的复杂度为$O(log m)$。

      总复杂度$O((n+m)log m)$。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=205,M=1000205;
    int n,m=0,p[N],len[N];
    int SA[M],rank[M],height[M],tmp[M],tax[M];
    int ST[M][22];
    char s[M];
    void Sort(int n,int m){
    	for (int i=0;i<=m;i++)
    		tax[i]=0;
    	for (int i=1;i<=n;i++)
    		tax[rank[i]]++;
    	for (int i=1;i<=m;i++)
    		tax[i]+=tax[i-1];
    	for (int i=n;i>=1;i--)
    		SA[tax[rank[tmp[i]]]--]=tmp[i];
    }
    bool cmp(int rk[],int x,int y,int w){
    	return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
    }
    void Suffix_Array(char s[],int n){
    	memset(SA,0,sizeof SA);
    	memset(tmp,0,sizeof tmp);
    	memset(rank,0,sizeof rank);
    	memset(height,0,sizeof height);
    	for (int i=1;i<=n;i++)
    		rank[i]=s[i],tmp[i]=i;
    	int m=127;
    	Sort(n,m);
    	for (int w=1,p=0;p<n;w<<=1,m=p){
    		p=0;
    		for (int i=n-w+1;i<=n;i++)
    			tmp[++p]=i;
    		for (int i=1;i<=n;i++)
    			if (SA[i]>w)
    				tmp[++p]=SA[i]-w;
    		Sort(n,m);
    		swap(rank,tmp);
    		rank[SA[1]]=p=1;
    		for (int i=2;i<=n;i++)
    			rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;
    	}
    	for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)
    		for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);
    }
    void Get_ST(int n){
    	memset(ST,0,sizeof ST);
    	for (int i=1;i<=n;i++){
    		ST[i][0]=height[i];
    		for (int j=1;j<22;j++){
    			ST[i][j]=ST[i][j-1];
    			if (i-(1<<(j-1))>0)
    				ST[i][j]=min(ST[i][j],ST[i-(1<<(j-1))][j-1]);
    		}
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++){
    		scanf("%s",s+m+1);
    		p[i]=m+1,len[i]=strlen(s+m+1);
    		m+=len[i]+1;
    		s[m]='#';
    	}
    	Suffix_Array(s,m);
    	Get_ST(m);
    	for (int i=1;i<=n;i++){
    		int ans=1,pos=rank[p[i]],L=len[i];
    		for (int j=21,now=pos;j>=0;j--)
    			if (now-(1<<j)>0&&ST[now][j]>=L)
    				now-=1<<j,ans+=1<<j;
    		for (int j=21,now=pos;j>=0;j--)
    			if (now+(1<<j)<=m&&ST[now+(1<<j)][j]>=L)
    				now+=1<<j,ans+=1<<j;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Qt Release 构建时强制包含调试信息
    Spring Kafka(二)操作Topic以及Kafka Tool 2的使用
    PostgreSQL全文检索简介
    qcow2虚拟磁盘映像转化为vmdk
    Nodejs-JWT token认证:为什么要使用token、token组成(头部、载荷、签名)、jwt使用过程以及token对比session的好处(单点登录、减轻服务器压力、存储信息等)
    [Kotlin] Multi ways to write constuctor in Kotlin
    [CSS] Use CSS Transforms to Create Configurable 3D Cuboids
    [CSS] Use CSS Variables Almost like Boolean Values with Calc (maintainable css)
    [Kotlin] Typecheck with 'is' keyword, 'as' keyword for assert type
    [Kotlin] When to add () and when not to
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ3172.html
Copyright © 2011-2022 走看看