关于排序

update 2.16

一个晚自修的想法

对一个序列a进行排序

如:a2 7 8 1 5 4

计算其“上坡”(上升序列),记录每个“上坡”的起始位置

如:(2 7 8) (1 5) (4)

记录起始位置为:

up[1]=1,up[2]=4,up[3]=6,up[4]=7up[4]记录a最后一位的下一位)

同理,记录“下坡”

down[1]=1,down[2]=2,down[3]=3,down[4]=5,down[5]=7

比较updown的长度,up更短,故以升序排序

对每两个相邻的“上坡”做一次merge操作,变化过程为:

(2 7 8) (1 5) (4)

(1 2 5 7 8) (4)

(1 2 4 5 7 8)

同理,若down更短,则降序排序后逆序输出(存储)

设“上坡”个数为p,“下坡”个数为q,则时间复杂度为:

O[min(p,q)n],(p,qn)

P1177实测代码

#include<cstdio>
int n;
int a[200000];
int up[200000];
int down[200000];
int uptot,downtot;
int now;
inline void merge(int l,int mid,int r,int type)
{
	int i=l,j=mid+1,k=l;
	int b[200000];
	while(i<=mid&&j<=r)
	{
		if(type==1)//up
		{
			if(a[i]<a[j]) b[k++]=a[i++];
			else b[k++]=a[j++];
		}
		else//down
		{
			if(a[i]>a[j]) b[k++]=a[i++];
			else b[k++]=a[j++];
		}
	}
	while(i<=mid) b[k++]=a[i++];
	while(j<=r) b[k++]=a[j++];
	for(i=l;i<=r;i++) a[i]=b[i];
}
inline void swap(int &x,int &y)
{
	int tmp=x;
	x=y;
	y=tmp;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	now=a[1];
	up[++uptot]=down[++downtot]=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i]<now) up[++uptot]=i;
		if(a[i]>now) down[++downtot]=i;
		now=a[i];
	}
	up[++uptot]=down[++downtot]=n+1;
	if(uptot<downtot)
		for(int i=1,j=2;j<uptot;j++) merge(up[i],up[j]-1,up[j+1]-1,1);
	else
	{
		for(int i=1,j=2;j<downtot;j++) merge(down[i],down[j]-1,down[j+1]-1,2);
		for(int i=1,j=n;i<j;i++,j--) swap(a[i],a[j]);
	}
	for(int i=1;i<=n;i++) printf("%d ",a[i]);
	return 0;
}

在最坏情况下,应该是p=q=12n,退化成O(n2)

#2会TLE,求优化方案

(什么LaTeX,不改成代码块都会变成一级标题)

update 2.18(偷偷用教室的电脑打的)

发现之前的搞错了,并不能比较数组长度

hack data:

1 2 3 4 5 6 7 8 7 6 5 4 3 2

显然,p=7,q=8,但:

升序需赋值:9+10+11+12+13+14=69

降序需赋值:2+3+4+5+6+7+14=41

故应:

[i=1p(pi+1)Pi]P1[i=1q(qi+1)Qi]Q1

则以升序排序

否则以降序排序

其中:Pi/Qi为第i个“上坡”/“下坡”的长度

#include<cstdio>
int n;
int a[200000];
int up[200000];
int down[200000];
int P[200000];
int Q[200000];
int sump,sumq;
int uptot,downtot;
int now;
inline void merge(int l,int mid,int r,int type)
{
	int i=l,j=mid+1,k=l;
	int b[200000];
	while(i<=mid&&j<=r)
	{
		if(type==1)//up
		{
			if(a[i]<a[j]) b[k++]=a[i++];
			else b[k++]=a[j++];
		}
		else//down
		{
			if(a[i]>a[j]) b[k++]=a[i++];
			else b[k++]=a[j++];
		}
	}
	while(i<=mid) b[k++]=a[i++];
	while(j<=r) b[k++]=a[j++];
	for(i=l;i<=r;i++) a[i]=b[i];
}
inline void swap(int &x,int &y)
{
	int tmp=x;
	x=y;
	y=tmp;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	now=a[1];
	up[++uptot]=down[++downtot]=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i]<now) up[++uptot]=i;
		if(a[i]>now) down[++downtot]=i;
		now=a[i];
	}
	up[++uptot]=down[++downtot]=n+1;
   
   for(int i=1;i<uptot;i++)
   {  
   		P[i]=up[i+1]-up[i];
  		 sump+=(uptot-i)*P[i];
  }
   for(int i=1;i<downtot;i++)
   {
   		Q[i]=down[i+1]-down[i];
  		 sumq+=(downtot-i)*Q[i];
   }
	if(sump<=sumq)
		for(int i=1,j=2;j<uptot;j++) merge(up[i],up[j]-1,up[j+1]-1,1);
	else
	{
		for(int i=1,j=2;j<downtot;j++) merge(down[i],down[j]-1,down[j+1]-1,2);
		for(int i=1,j=n;i<j;i++,j--) swap(a[i],a[j]);
	}
	for(int i=1;i<=n;i++) printf("%d ",a[i]);
	return 0;
}

时间复杂度为玄学(?)

然而TLE了更多(?,指#2和#4)

posted @   osfly  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示