bzoj-1031 字符加密Cipher

141 篇文章 0 订阅
75 篇文章 0 订阅

题意:

给出一个字符串,求将其所有循环串排序之后,每个串的最后一个字符;

字符串长度<=100000;


题解:

后缀数组裸题。。吧

学长拿这个当例题我还差点不会做。。。

反正就是把字符串倍增之后求后缀数组;

然后按后缀数组来扫一遍求解;

难点就是后缀排序(废话!);

这里用的是O(nlogn)的倍增+基数排序方法;

模板纯手写。。一堆for循环也是有毒。。

原理上就是利用倍增的思想,将每次的排序转化为二元组的排序问题;

而二元组的排序问题可以利用基数排序O(n)解决而已;

写代码的时候好费劲啊。。。码力果然不够强;

30行模板4数组,Orz PoPoQQQ 60行SA;


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 210000
#define S 256
using namespace std;
char str[N];
int rank[N],tr[N],hash[N],sa[N];
int main()
{
	int n,m,j,k,cnt;
	register int i;
	scanf("%s",str);
	n=strlen(str);
	memcpy(str+n,str,sizeof(char)*n);
	n<<=1;
	for(i=0;i<n;i++)		hash[str[i]]++;
	for(i=1,cnt=0;i<S;i++)	if(hash[i])	tr[i]=++cnt;
	for(i=1;i<S;i++)		hash[i]=hash[i-1]+hash[i];
	for(i=0;i<n;i++)		rank[i]=tr[str[i]];
	for(i=0;i<n;i++)		sa[--hash[str[i]]]=i;
	for(k=2;k<=n;k<<=1)
	{
		memset(hash,0,sizeof(hash));
		for(i=0;i<n;i++)	hash[rank[i]]++;
		for(i=1;i<=n;i++)	hash[i]=hash[i]+hash[i-1];
		for(i=n-1;i>=0;i--)	if(sa[i]>=(k>>1))tr[sa[i]-(k>>1)]=--hash[rank[sa[i]-(k>>1)]];
		for(i=1;i<=(k>>1);i++)	tr[n-i]=--hash[rank[n-i]];
		for(i=0;i<n;i++)	sa[tr[i]]=i;
		for(i=1,cnt=0;i<n;i++)
		if(rank[sa[i-1]]==rank[sa[i]]&&rank[sa[i-1]+(k>>1)]==rank[sa[i]+(k>>1)])	
		tr[sa[i]]=tr[sa[i-1]];
		else	tr[sa[i]]=++cnt;
		memcpy(rank,tr,sizeof(tr));
		if(cnt==n-1)
			break;
	}
	for(i=0;i<n;i++)
	{
		if(sa[i]<(n>>1))
			printf("%c",str[sa[i]+(n>>1)-1]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值