BZOJ 1692 队列变换 贪心+后缀数组

题目大意:给定一个字符串,每次取头或者尾放在新字符串里,求字典序最小的新字符串

首先如果两边的字符不一样 那么肯定要选择小的放在新字符串里

但如果两边一样 比如CCBACC 肯定从尾取比较优 原因是CCA比CCB要小

于是我们把原串反写接在后面变成[email protected] 然后跑一遍后缀数组 每次就能O(1)比较两个子串的大小了

时间复杂度O(nlogn)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 60600
using namespace std;
int n;
char s[M];
int X[M],Y[M],sa[M],rank[M];
int sum[M],cnt[M],temp[M],tot;
inline char Get_Char()
{
	char c;
	do c=getchar(); while(c==' '||c=='\t'||c=='\n'||c=='\r');
	return c;
}
void Get_Rank()
{
	int i,j;
	for(i=1;i<=n;i++)
		sum[s[i]]++;
	for(i=1;i<=127;i++)
		sum[i]+=sum[i-1];
	for(i=1;i<=n;i++)
		sa[ sum[s[i]-1]+ ++cnt[s[i]] ]=i;
	for(i=1;i<=n;i++)
	{
		if(i==1||s[sa[i]]!=s[sa[i-1]])
			++tot;
		rank[sa[i]]=tot;
	}
}
void Radix_Sort(int key[],int order[])
{
	int i;
	for(i=0;i<=n;i++)
		sum[i]=cnt[i]=0;
	for(i=1;i<=n;i++)
		sum[key[i]]++;
	for(i=1;i<=n;i++)
		sum[i]+=sum[i-1];
	for(i=1;i<=n;i++)
		temp[ sum[key[order[i]]-1]+ ++cnt[key[order[i]]] ]=order[i];
	for(i=1;i<=n;i++)
		order[i]=temp[i];
}
void Prefix_Doubling()
{
	int i,j;
	Get_Rank();
	for(j=1;j<=n;j<<=1)
	{
		for(i=1;i<=n;i++)
		{
			X[i]=rank[i];
			Y[i]=i+j>n?0:rank[i+j];
			sa[i]=i;
		}
		Radix_Sort(Y,sa);
		Radix_Sort(X,sa);
		for(i=1,tot=0;i<=n;i++)
		{
			if( i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]] )
				++tot;
			rank[sa[i]]=tot;
		}
	}
}

int main()
{
	int i,j=0;
	cin>>n;
	s[n+1]='A'-1;
	for(i=1;i<=n;i++)
		s[n+1-i]=s[n+1+i]=Get_Char();
	n=n<<1|1;
	Prefix_Doubling();
	int l=1,r=n>>1;
	while(l<=r)
	{
		++j;
		if(s[l]<s[r]) putchar(s[l++]);
		else if(s[l]>s[r]) putchar(s[r--]);
		else if(rank[l]<rank[n+1-r]) putchar(s[l++]);
		else putchar(s[r--]);
		if(j%80==0) puts("");
	}
}
时间: 2024-10-10 08:25:02

BZOJ 1692 队列变换 贪心+后缀数组的相关文章

[BZOJ 1692] [Usaco2007 Dec] 队列变换 【后缀数组 + 贪心】

---恢复内容开始--- 题目链接:BZOJ - 1692 题目分析 首先,有个比较简单的贪心思路:如果当前剩余字符串的两端字母不同,就选取小的字母,这样显然是正确的. 然而若两端字母相同,我们怎么选取呢? 这时我们要从两端分别向内部比较,看那一端向内的字符串字典序小. 比如这个字符串 ABCDBA,从左端向内是 ABC.. 从右端向内是 ABD... 所以就选取左端的字符. 这样直接比较是 O(n^2) 的,我们可以使用后缀数组的 Rank 数组来比较. 我们在字符串后加上分隔符,然后再将字符

[bzoj1692][Usaco2007 Dec]队列变换_后缀数组_贪心

队列变换 bzoj-1692 Usaco-2007 Dec 题目大意:给定一个长度为$n$的字符串.每次从头或尾取出一个字符加到另一个字符串里.要求变换后生成的字符串字典序最小,求字典序最小的字符串. 注释:$1\le n\le 3\cdot 10^4$. 想法: 考虑暴力怎么做: 每次把当前字符串左右较小的取出来.如果一样就对着往中间枚举,直到不一样为止. 这样时间复杂度为$O(n^2)$,全是一样的字符即可卡掉. 显然上述过程我们就是比较正反两个字符串谁的字典序更小对吧. 那么我们把原串翻转

[Luogu2870] [USACO07DEC]最佳牛线Best Cow Line(贪心+后缀数组)

[Luogu2870] [USACO07DEC]最佳牛线Best Cow Line(贪心+后缀数组) 题面 FJ打算带他的\(N(1 \leq N \leq 30,000)\)头奶牛去参加一年一度的"全美农场主大奖赛".在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席前依次走过. 今年,竞赛委员会在接受队伍报名时,采用了一种新的登记规则:他们把所有队伍中奶牛名字的首字母取出,按它们对应奶牛在队伍中的次序排成一列(比如说,如果FJ带去的奶牛依次为Bessie.Sylv

BZOJ 1692: [Usaco2007 Dec]队列变换( 贪心 )

数据 n <= 30000 , 然后 O( n² ) 的贪心也过了..... USACO 数据是有多弱啊 = = ( ps : BZOJ 1640 和此题一模一样 , 双倍经验 ) -------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #

[贪心+后缀数组] poj 3623 Best Cow Line, Gold

题意: 给N个字符,每次只能取第一个或者最后一个,问构成最小字典序的串是什么. 思路: 贪心,每次取字典序最小的串,的首字符. 其实就是l和r比较一下构成的串那个字典序小. 这里运用后缀数组要实现O(1)的查询. 将原串反拼进串内做da. 然后根据ra判断. 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include&quo

POJ3617:Best Cow Line (贪心&amp;&amp;后缀数组)

FJ is about to take his N (1 ≤ N ≤ 2,000) cows to the annual"Farmer of the Year" competition. In this contest every farmer arranges his cows in a line and herds them past the judges. The contest organizers adopted a new registration scheme this

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ----------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ty

BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; typedef long long