交了两页了,救救孩子吧
查看原帖
交了两页了,救救孩子吧
93266
断清秋楼主2022/3/10 17:48

思路是用 deque 模拟,然后启发式合并。

lstilst_i 表示第 ii 块的上一个非空块,nxtinxt_i 表示第 ii 块的下一个非空块,empi=1emp_i=1 表示第 ii 块为空。

调了整整三个小时,有 WA 有 TLE 有 MLE,实在受不了了。

#include<bits/stdc++.h>
#define ll long long
#define ri register int
#define back return
using namespace std;
ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	back x*f;
}
int n,sum,cnt,nxt[200005],emp[200005],f[200005],lst[200005];
deque<int> a[200005];
int main()
{
   	n=read();
   	int last=-1;
   	for(ri i=1;i<=n;i++)
   	{
   		int x=read();
   		if(x==last)
   			a[cnt].push_back(i);
   		else
   			a[++cnt].push_back(i),nxt[cnt-1]=cnt,lst[cnt]=cnt-1;
   		last=x;
   	}
   	int l=1,r=cnt;
   	while(sum<n)
   	{
   		while(emp[l])
   			l++;
   		while(emp[r])
   			r--;
	   	for(ri i=l;i<=r;i++)
	   	{		
		   	if(emp[i])
		   		continue;
	   		cout<<a[i].front()<<" ",sum++;
	   		a[i].pop_front();
	   		if(i==r)
	   			cout<<"\n";  			
	   	}
	   	for(ri i=l;i<=r;i++)//启发式合并
	   	{
	   		if(emp[i]&&!f[i])
	   			continue;
	   		f[i]=0;//判断这个空块是不是刚刚才变空的
	   		if(!a[i].size()||emp[i])
	   		{
	   			emp[i]=1;
	   			if(i==l)
	   				continue;
	   			if(i==r)
	   				break;
	   			if(a[lst[i]].size()>a[nxt[i]].size())
	   			{
		   			for(ri j=0;j<a[nxt[i]].size();j++)
		   				a[lst[i]].push_back(a[nxt[i]][j]);
		   			nxt[lst[i]]=nxt[nxt[i]];
		   			emp[nxt[i]]=1,f[nxt[i]]=1;
	   			}
	   			else
	   			{
	   				for(ri j=a[lst[i]].size()-1;j>=0;j--)
	   					a[nxt[i]].push_front(a[lst[i]][j]);
	   				lst[nxt[i]]=lst[lst[i]];
	   				emp[lst[i]]=1,f[lst[i]]=1;
	   			}
	   		}
	   	}
   	} 	
    back 0;
}
2022/3/10 17:48
加载中...