BZOJ 1692 [Usaco2007 Dec]队列变换 贪心+后缀数组_syx1692_MyZhY的博客-程序员宅基地

技术标签: 后缀数组,后缀自动机  贪心  

Description

FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”。在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席前依次走过。 今年,竞赛委员会在接受队伍报名时,采用了一种新的登记规则:他们把所有队伍中奶牛名字的首字母取出,按它们对应奶牛在队伍中的次序排成一列(比如说,如果FJ带去的奶牛依次为Bessie、Sylvia、Dora,登记人员就把这支队伍登记为BSD)。登记结束后,组委会将所有队伍的登记名称按字典序升序排列,就得到了他们的出场顺序。 FJ最近有一大堆事情,因此他不打算在这个比赛上浪费过多的时间,也就是说,他想尽可能早地出场。于是,他打算把奶牛们预先设计好的队型重新调整一下。 FJ的调整方法是这样的:每次,他在原来队列的首端或是尾端牵出一头奶牛,把她安排到新队列的尾部,然后对剩余的奶牛队列重复以上的操作,直到所有奶牛都被插到了新的队列里。这样得到的队列,就是FJ拉去登记的最终的奶牛队列。 接下来的事情就交给你了:对于给定的奶牛们的初始位置,计算出按照FJ的调整规则所可能得到的字典序最小的队列。

Input

* 第1行: 一个整数:N

* 第2..N+1行: 第i+1行仅有1个'A'..'Z'中的字母,表示队列中从前往后数第i 头奶牛名字的首字母

Output

* 第1..??行: 输出FJ所能得到的字典序最小的队列。每行(除了最后一行)输 出恰好80个'A'..'Z'中的字母,表示新队列中每头奶牛姓名的首 字母

Sample Input

6
A
C
D
B
C
B

输入说明:

FJ有6头顺次排好队的奶牛:ACDBCB

Sample Output

ABCBCD

输出说明:

操作数 原队列 新队列
#1 ACDBCB
#2 CDBCB A
#3 CDBC AB
#4 CDB ABC
#5 CD ABCB
#6 D ABCBC
#7 ABCBCD

HINT




首先我们可以得到一个贪心的想法:
每次从头和尾之间取最优,即局部最优,然后得到一个串。
那么为什么这是正确的呢?……
我们分两种情况讨论。
1:头<尾或者头>尾
      这种情况下,选什么应该是很明显的。
      假如我们选了更大的那个,换成另一个总能得到更优的解。
      所以这种情况下我们直接就可以作出选择。
2:头=尾
      这个时候我们不能马上做出选择了……
      但是我们知道要选择一个后面更优的。
      比如说ABCA,那么显然我们会选择取头的A,因为AB<AC.

在上面的例子中, 不妨换个角度:ABCA<ACBA.
即从头开始到len位置,和从尾开始到1位置的两个串,它们之间有一个大小的比较。
我们可以看到这样子的比较的结果,
其实就是我们想要人为进行比较的结果。

对于2,我们想要相等时,指针推进,直到分出胜负为止;显然这是会TLE的。
但是刚才的想法,让我们能够想到后缀排序方面。

我们只要让原串反过来,再接到原串的后方,接着求出这个串的sa和rank即可。
举个简单的例子:刚才的ABCA。
首先我们接一个字符,这个字符不要是A..Z即可,我接了[。
那么变成ABCA[ACBA
然后当我们选择原串1,4位置的时候,
其实4位置对应了后面的6位置;
所以判断1,6位置的rank大小即可。显然rank[1]<rank[6],那么取1.
以此类推。

注意此题有坑点啊……
输出的格式非常难受= =
气死了每80个一行WA了一次。。。
然后发现末尾还必须换行又WA了一次……



#include<bits/stdc++.h>
using namespace std;
const int 
	N=60006; //N<<1
int n;
char s[N];
int cnta[N],cntb[N],a[N],b[N];
int tsa[N],sa[N],rank[N<<1];
void Get_SA(){
	for (int i=0;i<27;i++) cnta[i]=0;
	for (int i=1;i<=n;i++) cnta[s[i]-'A']++;
	for (int i=1;i<27;i++) cnta[i]+=cnta[i-1];
	for (int i=n;i;i--) sa[cnta[s[i]-'A']--]=i;
	rank[sa[1]]=1;
	for (int i=2;i<=n;i++)
		rank[sa[i]]=rank[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
	for (int j=1;rank[sa[n]]!=n;j<<=1){
		for (int i=1;i<=n;i++) a[i]=rank[i],b[i]=rank[i+j];
		for (int i=0;i<=n;i++) cnta[i]=cntb[i]=0;
		for (int i=1;i<=n;i++) cnta[a[i]]++,cntb[b[i]]++;
		for (int i=1;i<=n;i++) cnta[i]+=cnta[i-1],cntb[i]+=cntb[i-1];
		for (int i=n;i;i--) tsa[cntb[b[i]]--]=i;
		for (int i=n;i;i--) sa[cnta[a[tsa[i]]]--]=tsa[i];
		rank[sa[1]]=1;
		for (int i=2;i<=n;i++)
			rank[sa[i]]=rank[sa[i-1]]+
				(a[sa[i]]!=a[sa[i-1]] || b[sa[i]]!=b[sa[i-1]]);
	}
}
int main(){
	scanf("%d",&n);
	getchar();
	for (int i=1;i<=n;i++)
		s[i]=getchar(),getchar();
	s[n+1]='[';  //'z'+1
	for (int i=n;i;i--) s[n+n-i+2]=s[i];
	n=n<<1|1;
	
	Get_SA();
	
	int m=n>>1,tm=m,L=1,R=1;
	while (tm--){
		if (rank[L]<rank[R+m+1]){
			printf("%c",s[L]);
			L++;
		}	else{
			printf("%c",s[R+m+1]);
			R++;
		}
		if (!((m-tm)%80)) puts("");
	}
	if (m%80) puts("");
	return 0;
}



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ThinFatty/article/details/76167586

智能推荐

使用struts2-convention-plugin-2.2.1.1.jar插件实现基于注解的配置。-程序员宅基地

部分代码(语法格式)如下:@ParentPackage("struts-default")@Action(value = "login",results{@result(name="success",location="/result.jsp"),@result(name="input",location="login.jsp")})public class Login

java8 新特性-----Lambda表达式、Stream、Optional_鸦教授的博客-程序员宅基地

文章目录一、Lambda表达式1、函数式编程的思想2、什么是lambda表达式:实现函数式接口的语法3、接口的分类3.1、消费型接口:有参无返回值3.2、供给型接口:无参有返回值3.3、判断型接口:有参有返回值,但是返回值类型是boolean类型3.4、功能型接口:有参有返回值3.5、自定义函数式接口4、Lambda表达式语法4.1、Lambda的优化/简化5、方法引用与构造器引用5.1、方法引用5.2、构造器引用二、Stream API1、定义2、作用3、Stream特

count(*)查询性能很差?用这5招轻松优化_clickhouse count慢-程序员宅基地

最近我在公司优化过几个慢查询接口的性能,总结了一些心得体会拿出来跟大家一起分享一下,希望对你会有所帮助。我们使用的数据库是Mysql8,使用的存储引擎是Innodb。这次优化除了优化索引之外,更多的是在优化count(*)。通常情况下,分页接口一般会查询两次数据库,第一次是获取具体数据,第二次是获取总的记录行数,然后把结果整合之后,再返回。查询具体数据的sql,比如是这样的:`它没有性能问题。却存在性能差的问题。为什么会出现这种情况呢?_clickhouse count慢

分治算法-最邻近点问题Finding the closest pair of points_最邻近点对-程序员宅基地

问题描述:输入:空间平面上点集Q 输出:距离最近的两个点对问题简化:如果是在一个直线上找最近的点对,则可以使用排序,之后找最近最近点。分治思路:Divide 将其划分为两个部分Q1,Q2 T(n) = O(n)Conquer 分别找最近点对, T(n) = 2T(n/2)Merge 比较分开点附近的两个点距离和找出的的距离T(n)= O(_最邻近点对

vue设置代理不起作用解决办法_vue3使用proxy.target配置请求链接不生效 csdn_姜意%的博客-程序员宅基地

使用vue写前端界面时,需调用后端接口展现查询的数据,于是设置代理实现跨域,在config/index.js中添加代理,代码如下:proxyTable:{ // 匹配 /dev-api 开头的请求, 比如:A网站:https://localhost:8888 中的index.html 页面发送AJax请求:/dev-api/data.json 'dev-api': { target:'http://localhost:3001', // 开启代理:在_vue3使用proxy.target配置请求链接不生效 csdn

Linux(SUSE 12)安装mysql-程序员宅基地

安装的4个rpm包为mysql-community-common-5.6.26-2.sles12mysql-community-libs-5.6.26-2.sles12mysql-community-common-5.6.26-2.sles12.x86_64.rpmmysql-community-server-5.6.26-2.sles12.x86_64 先

随便推点

剪枝简述(模型压缩加速篇)-程序员宅基地

模型压缩:剪枝(Pruning)量化(Quantization)低秩分解(Low-rank factorization)知识蒸馏(Knowledge distillation)剪枝为什么可以剪枝深度神经网络可分为训练和推理两个阶段。训练阶段是根据数据学习模型中的参数(对神经网络来说主要是网络中的权重);推理阶段中将新数据喂进模型,经过计算得出结果。而过参数化是指训练阶段我们需要大量的参数来捕捉数据中的微小信息,而一旦训练完成到了推理阶段,我们并不需要这么多的参数。这样的假设就支持我们可

行人属性分类算法:自适应权重多任务学习_行人分类-程序员宅基地

论文:http://www.yugangjiang.info/publication/17MM-PersonAttribute.pdfgithub地址:https://github.com/qiexing/adaptive_weighted_attributeAdaptively Weighted Multi-task Deep Network for Person A!ribute Cl..._行人分类

数学图形(1.4)心形线-程序员宅基地

心形线,是一个圆上的固定一点在它绕着与其相切且半径相同的另外一个圆周滚动时所形成的轨迹,因其形状像心形而得名。当然我觉得与其说它像心,还不如说它像屁股。 相关软件参见:数学图形可视化工具,使用自己定义语法的脚本代码生成数学图形.该软件免费开源.QQ交流群: 367752815 极坐标方程:..._心形线怎么更像心

MySQL数据库_mysql数据库object-程序员宅基地

MySQL数据库事务事务及四大特征什么是事务数据库事务(Database Transaction),是指作为单个逻辑工作单元执行的一系列操作,要么完全的执行,要么完全的不执行。简单的说:事务就是将一堆的SQL语句(通常是增删改查操作)绑定在一起执行,要么都执行成功,要么都执行失败,即都执行成功才算成功,否则就会恢复到这堆SQL执行之前的状态。下面以银行转账为例,张三转100块到李四的账户,这至少需要两条SQL语句:给张三的账户减去100元;update 账户表 set money = mone_mysql数据库object

win7 JDK配置-程序员宅基地

.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar