zoukankan      html  css  js  c++  java
  • Luogu4051/BZOJ1031 [JSOI2007]字符加密

    题目传送门

    算法分析

    这题相当于对环形字符串进行后缀排序,处理环上问题的一般策略是破环为链,将原字符串复制一倍接在原字符串后面,然后对这个新字符串进行后缀排序。

    为什么这个算法是对的?后缀中\(>n\)那一部分字符串会不会影响答案?

    因为我们只关注新的字符串后缀前\(n\)位,并且只有两个后缀满足\(n\)位完全相同时才会进行后面的比较,这种情况只会在形如aaaaa这种字符串中出现,显然这种字符串无论是什么排序顺序都不会影响结果。

    注意空间开2倍!!!

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 200005//错误笔记:复制二倍数组没开够 
    #define maxm 400005
    char s[maxn];
    int n;
    int sa[2][maxn],rk[2][maxn],v[maxn];
    int main(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	for(int i=1;i<=n;i++)s[i+n]=s[i];
    	n=strlen(s+1);
    	int p=0,q=1;
    	for(int i=1;i<=n;i++)v[s[i]]++;
    	for(int i=1;i<128;i++)v[i]+=v[i-1];
    	for(int i=1;i<=n;i++)sa[0][v[s[i]]--]=i;
    	for(int i=1;i<=n;i++)rk[0][sa[0][i]]=rk[0][sa[0][i-1]]+(s[sa[0][i-1]]!=s[sa[0][i]]);
    	for(int k=1;k<=n;(k<<=1),swap(p,q)){
    		for(int i=1;i<=n;i++)v[rk[p][sa[p][i]]]=i;
    		for(int i=n;i;i--)
    			if(sa[p][i]>k)sa[q][v[rk[p][sa[p][i]-k]]--]=sa[p][i]-k;
    		for(int i=n-k+1;i<=n;i++)sa[q][v[rk[p][i]]--]=i;
    		for(int i=1;i<=n;i++)rk[q][sa[q][i]]=rk[q][sa[q][i-1]]+((rk[p][sa[q][i]]!=rk[p][sa[q][i-1]])||(rk[p][sa[q][i]+k]!=rk[p][sa[q][i-1]+k]));
    		if(rk[q][sa[q][n]]==n)break;
    	}
    	for(int i=1;i<=n;i++)
    		if(sa[q][i]<=n/2)printf("%c",s[sa[q][i]+n/2-1]);
    	return 0;
    }
    
  • 相关阅读:
    语言基础
    进制转换
    Java基础相关
    Java基础了解
    php 条件查询和多条件查询
    php 增删改查练习
    php 用封装类的方法操作数据库和批量删除
    php 用面向对象的方法对数据库增删改查
    php 面向对象的方式访问数据库
    OOP 7大原则
  • 原文地址:https://www.cnblogs.com/ZigZagKmp/p/11479796.html
Copyright © 2011-2022 走看看