• 【题解】[JSOI2007]字符加密


    Link

    ( ext{Solution:})

    后缀数组第一题祭……

    观察一下,这个是让求一个环形的原字符串的后缀,我们可以考虑一下断环为链。

    对于(aba)我们扩展成(abaaba,)则一个后缀(baa)对应的就是(baaba,aba)对应的就是(abaaba).

    那么,两个扩展后的后缀如果要比大小,则要从前向后一个个比较。也就是说,对于原来环形串上的段,它们的排名其实是不变的。因为前一段包括这一段的部分是不变的,又因为它从前向后比较,所以相对排名不变。

    那么,我们将原串扩展为两倍后,进行后缀排序。

    对于已经知道的(sa[i])我们从小到大枚举(i)(根据题意,排名从小到大),并且判断这个起点是不是可以包含一段对应的后缀。如果包含,我们就把它对应的那一段的最后一个字符输出即可。

    后缀数组我们可以做到(O(nlog n).)

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=2e6+10;
    char s[MAXN];
    int rk[MAXN],sa[MAXN],o[MAXN<<1],n,m=200,px[MAXN],cnt[MAXN],id[MAXN];
    inline bool cmp(int x,int y,int w){return o[x]==o[y]&&o[x+w]==o[y+w];}
    #define D cout<<"qwq
    ";
    int main(){
    	cin>>(s+1);
    	n=strlen(s+1)<<1;
    	//D
    	for(int i=1;i<=(n/2);++i)s[i+(n/2)]=s[i];
    //	for(int i=1;i<=n;++i)cout<<s[i];
    //	cout<<endl;
    	for(int i=1;i<=n;++i)++cnt[rk[i]=s[i]];
    	for(int i=1;i<=m;++i)cnt[i]+=cnt[i-1];
    	for(int i=n;i>=1;--i)sa[cnt[rk[i]]--]=i;
    	int p,w;
    	//D
    	for(w=1;w<=n;w<<=1,m=p){
    		p=0;
    		for(int i=n;i>n-w;--i)id[++p]=i;
    		for(int i=1;i<=n;++i)if(sa[i]>w)id[++p]=sa[i]-w;
    		fill(cnt,cnt+m+1,0);
    		for(int i=1;i<=n;++i)++cnt[px[i]=rk[id[i]]];
    		for(int i=1;i<=m;++i)cnt[i]+=cnt[i-1];
    		for(int i=n;i>=1;--i)sa[cnt[px[i]]--]=id[i];
    		memcpy(o,rk,sizeof(rk));p=0;
    		for(int i=1;i<=n;++i)rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
    		if(m==n)break;
    		//D
    	}
    //	for(int i=1;i<=n;++i)cout<<sa[i]<<" ";
    //	cout<<endl;
    	for(int i=1;i<=n;++i){
    		if(sa[i]<=n/2)cout<<s[sa[i]+n/2-1];
    	}
    	//JSOI07JSOI07
    	return 0;
    }
    
  • 相关阅读:
    [洛谷P4513][题解]小白逛公园
    [洛谷P2564][题解][SCOI2009]生日礼物
    [洛谷P3384][题解]轻重链剖分
    [洛谷P2607][题解][ZJOI2008]骑士
    第一次个人编程作业
    第一次博客作业
    第一次个人编程作业
    第一次博客作业
    1.初识数据库系统
    1.计算机发展历程
  • 原文地址:https://www.cnblogs.com/h-lka/p/12862380.html
Copyright © 2020-2023  润新知