2020牛客暑期多校训练营(第一场)B-Suffix Array (后缀数组+思维)

news/2024/7/1 21:14:57

LINK

题意

给出长度为 n n n的字符串,现在每个后缀都可以生成一个对应的序列

求这 n n n个后缀生成的序列按照字典序排序的顺序,从小到大输出。


由于只有两个字母 a , b a,b a,b,考虑到第一个出现的字母 a a a和字母 b b b在序列都是数字 0 0 0

所以每个后缀的前缀序列一定是 01...10 01...10 01...10的形式(中间可能没有 1 1 1)

我们称之为 A A A部分,其余部分称为 ∣ B ∣ |B| B部分

A A A部分长度越小的,字典序越小(很显然吧,都是 01..10 01..10 01..10的形式嘛)

A A A部分长度相同的,就都去掉 A A A部分,比较后缀序列的大小

我们惊人的发现,去掉 A A A部分后, ∣ B ∣ |B| B部分刚好是原串形成的序列的后缀!!!

问题是有些后缀没有 ∣ B ∣ |B| B部分,那么该后缀的形式一定是 011111...1 011111...1 011111...1的形式,设长度为 ∣ A ∣ |A| A

那么比较大小的时候若 ∣ A ∣ |A| A小于其他串的 ∣ A ∣ |A| A,那么排在前面,否则排在后面

那么对于开头位置分别是 a , b , c a,b,c a,b,c来说

实际上就是比较 a + ∣ A ∣ , b + ∣ A ∣ , c + ∣ A ∣ a+|A|,b+|A|,c+|A| a+A,b+A,c+A的后缀序列大小,这部分可以由 s a sa sa数组求得

于是问题就解决了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int n,m,x[maxn],y[maxn],sa[maxn],c[maxn],a[maxn],rk[maxn],las[maxn];
char s[maxn];
struct p
{
	int id,A,nxt,flag;
	bool operator < (const p&t ) const
	{
		if( flag )	return A<t.A;
		if( t.flag )	return A<=t.A;
		if( A!=t.A )	return A<t.A;
		else	return rk[nxt]<rk[t.nxt];
	}
}vec[maxn];
//void SA(int n)
void SA(int n,int x[],int y[])
{
	int m = n;
	for(int i=1;i<=n;i++)	++c[x[i]=a[i]];
	for(int i=1;i<=m;i++)	c[i] += c[i-1];
	for(int i=n;i>=1;i--)	sa[c[x[i]]--] = i;
	for(int k=1;k<=n;k<<=1)
	{
		int num = 0;
		for(int i=n-k+1;i<=n;i++)	y[++num] = i;
		for(int i=1;i<=n;i++)	if( sa[i]>k )	y[++num] = sa[i]-k;
		for(int i=0;i<=m;i++)	c[i] = 0;
		for(int i=1;i<=n;i++)	++c[x[i]];
		for(int i=1;i<=m;i++)	c[i] += c[i-1]; 
		for(int i=n;i>=1;i--)	sa[c[x[y[i]]]--] = y[i], y[i] = 0;
		swap(x,y);
		x[sa[1]] = 1, num = 1;
		for(int i=2;i<=n;i++)
			x[sa[i]] = ( y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] )?num:++num; 	
		if( num==n )	break;
		m = num;//只有这么多种类型 
	}
	for(int i=1;i<=n;i++)	rk[sa[i]] = i;
}
int main()
{
	while( scanf("%d%s",&n,s+1 )!=EOF )
	{
		las['a'] = las['b'] = 0;
		for(int i=1;i<=n;i++)
		{
			if( las[s[i]] )	a[i] = i-las[s[i]];
			else	a[i] = 0;
			las[s[i]] = i;
		}	
	//	SA(n);
		SA(n,x,y);
		las['a'] = las['b'] = 0;
		for(int i=n;i>=1;i--)
		{
			if( s[i]=='a' )
			{
				int l = las['b']-i+1;
				if( las['b'] )
				{
					vec[i].flag = 0;
					vec[i].nxt = i+l, vec[i].A = l;
				}
				else
					vec[i].flag = 1,vec[i].A = n-i+1;					
			}
			else
			{
				int l = las['a']-i+1;
				if( las['a'] )
				{
					vec[i].flag = 0;
					vec[i].nxt = i+l, vec[i].A = l;
				}
				else	vec[i].flag = 1,vec[i].A = n-i+1;
			}
			las[s[i]] = i; vec[i].id = i;
		}
		sort( vec+1,vec+1+n );
		for(int i=1;i<=n;i++)
		{
			printf("%d ",vec[i].id);
			rk[i] = sa[i] = x[i] = y[i] = c[i] = a[i] = 0;
			vec[i].id = vec[i].flag = vec[i].A = vec[i].nxt = 0;
		}
		puts("");
	}
}

http://www.niftyadmin.cn/n/3620863.html

相关文章

CSS3笔记4

1.CSS3盒子模型 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>Document</title>6 <style>7 div:first-child {8 width: 200px;9 height: 200p…

linux 失败无连接 检查电缆吗

将BOOTPROTOdhcp改成 BOOTPROTOstatic 改成手动获取IP的模式 原因: 虚拟机中的Linux目前是默认设成的自动获取IP设置&#xff0c;但你的网络中没有DHCP服务&#xff0c;所以会显示“正在决定eth0的IP信息。。。失败&#xff1a;无链接。检查电缆吗&#xff1f; 【失败】”

P3469 [POI2008]BLO-Blockade(tarjan搜索树)

LINK 使用tarjantarjantarjan求出割点,显然非割点的答案是2∗(n−1)2*(n-1)2∗(n−1) 如果是割点,割掉之后,会把原图分成若干个连通块 下面的讨论暂时不计算点uuu的贡献 考虑在tarjantarjantarjan形成的dfsdfsdfs树中 uuu的儿子分别是v1,v2,v3...v_1,v_2,v_3...v1​,v2​,v…

ifconfig 工具

ifconfig 工具 ifconfig 命令常用格式 格式&#xff1a;ifconfig显示当前激活的网络接口信息。 格式&#xff1a;ifconfig {INTERFACE}显示指定网络接口的信息。比如&#xff1a;eth0, eth1。 格式&#xff1a;ifconfig -a显示所有网络接口的信息&#xff0c;无论是否激活。 格…

开学第六周.ONE(区间DP)

不知不觉已经第六周了&#xff0c;感觉什么都没学到似的&#xff0c;老师讲的东西有的我现在还没消化&#xff0c;以至于我感觉已经跟不上老师的进度&#xff0c;这其实很悲哀&#xff0c;对于DP的有些东西我还是理解不了&#xff0c;为什么这个状态转移方程可以这样写&#xf…

Expert 诊断优化系列------------------内存不够用么?

现在很多用户被数据库的慢的问题所困扰&#xff0c;又苦于花钱请一个专业的DBA成本太高。软件维护人员对数据库的了解又不是那么深入&#xff0c;所以导致问题迟迟不能解决&#xff0c;或只能暂时解决不能得到根治。开发人员解决数据问题基本又是搜遍百度各种方法尝试个遍&…

训练总结 18.7.17 暑假训练第二天

今日完成题量两道题&#xff0c;真是越来越少了。 所谓的思维题&#xff0c;实在是想不上。今天那个图形题&#xff0c;推规律只能推出一半&#xff0c;不看题解完全做不出来&#xff0c;比较凉。

Azure 基础:用 PowerShell 自动登录

PowerShell 是管理 Azure 的最好方式&#xff0c;因为我们可以使用脚本把很多的工作自动化。比如把 Azure 上的虚拟机关机&#xff0c;并在适当的时间把它开机&#xff0c;这样我们就能节省一些开支&#xff0c;当然我们同时也为减少二氧化碳的排放做出了贡献&#xff01; Powe…