zoukankan      html  css  js  c++  java
  • 2020牛客多校第一场 B题Suffix Array(结论+后缀数组)

    2020牛客多校第一场 B题Suffix Array(结论+后缀数组)

    B-Suffix Array

    刚学后缀数组有点菜没a出来,看题解后,是个结论没发现:

    • Let C_i = min_{j > i and s_j = s_i} {j - i}
    • The B-Suffix Array is equivalent to the suffix array of C_1 C_2 ... C_n

    这是题解的原话,我给大家翻译一下,c[i]的值是索引i后面离它最近的与s[i]同字符的距离,然后字符串的后缀数组就与这个c数组的后缀数组,这个结论只适用于只有两个字符的情况,所以题目字符也只有两种a与b,怎么证明的话大家去看官方证明吧,本人过菜,我是看半天没看明白,orz。

    不过我可以给大家演示一下。(注意如果是最后的a,b的话它后面无a,b那么结果是无穷大,我这边就让他等于n了,最后一位让它加一位为n+1)。

    如abaab的c数组为231556,列出c的后缀为:

    231556,31556,1556,556,56,6

    所以,sa数组就是312456,反过来54213就是答案了。

    我的写法是把231556变成32400-1,这样比较契合我的写法,不用大改cmp。

    代码,之前看过其他大佬的,都写得很多,好像不是这么做的,可能是自己想出来的神仙写法吧orz。

    还有我的后缀数组板子的话用的是书上的,比大家的短很多,主要我刚学,也不清楚他们那种是不是有什么优化,希望大佬指点迷津,以下是ac代码。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,c[100007];
    string s;
    int ran[100007],tmp[100007],sa[100007],k;
    void init(){
    	k=0;
    	memset(ran,0,sizeof(ran));
    	memset(tmp,0,sizeof(tmp));
    	memset(c,0,sizeof(c));
    }
    bool cmp(int i,int j){
    	if(ran[i]!=ran[j]) return ran[i]<ran[j];
    	else{
    		int ri,rj;
    		if(i+k<=n){
    			ri=ran[i+k];
    		}
    		else{
    			ri=-1;
    		}
    		if(j+k<=n){
    			rj=ran[j+k];
    		}
    		else{
    			rj=-1;
    		}
    		return ri<rj;
    	}
    }
    void get_sa(int sa[]){
    	for(int i=0;i<=n;i++){
    		sa[i]=i;
    		if(i<n){
    			ran[i]=c[i];
    		}
    		else{
    			ran[i]=-1;
    		}
    	}
    	for(k=1;k<=n;k*=2){
    		sort(sa,sa+n+1,cmp);
    		tmp[sa[0]]=0;
    		for(int i=1;i<=n;i++){
    			tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i]) ? 1 : 0);
    		}
    		for(int i=0;i<=n;i++){
    			ran[i]=tmp[i];
    		}
    	}
    }
    int main(){
    	while(~scanf("%d",&n)){
    		cin>>s;
    		int a=n,b=n;
    		for(int i=n-1;i>=0;i--){
    			if(s[i]=='a'){
    				if(a==n)c[i]=(n-a)%n;
    				else c[i]=(n-a+i)%n;
    				a=i;
    			}
    			else{
    				if(b==n)c[i]=(n-b)%n;
    				else c[i]=(n-b+i)%n;
    				b=i;
    			}
    		}
    		get_sa(sa);
    		for(int i=1;i<=n;i++){
    			printf("%d ",sa[i]+1);
    		}puts("");
    	}
    
    }
    
    
  • 相关阅读:
    笔记20200430:异常机制
    笔记20200429:面向对象
    笔记20200429:数组
    笔记20200428:方法的定义及调用、重装、命令行参数、可变参数、递归
    笔记20200427:javadoc文档、Scanner、顺序结构、选择结构、循环结构
    CSS+DIV入门第一天基础视频 CSS选择器层叠性和继承性
    网站实战 从效果图开始CSS+DIV 布局华为网站
    CSS中的间距设置与盒子模型
    CSS选择器
    CSS颜色及文本字体
  • 原文地址:https://www.cnblogs.com/whitelily/p/13290140.html
Copyright © 2011-2022 走看看