題目傳送門
正解
思路
開兩個鏈表,維護單個水果和每個塊的最左端,暴力模擬即可。
難點主要在於每個塊最左端的合並。
令當前需要刪除的位置為 NOW ,那么:
-
NOW 的前驅的后繼的處理:
- 如果 NOW 無前驅:那還管他干什么呢,直接略過
- 如果 NOW 有前驅但無后繼:該前驅將不會有后繼,指向 END
- 如果 NOW 有前驅但只有一個后繼:不難證明該后繼會與該前驅合並,而且合並后該前驅將不會再有后繼,所以指向 END
- 如果 NOW 有前驅但有兩個及以上的后繼:與 iii 相似,但是合並后將仍有后繼,該后繼即 NOW 的后繼 的后繼
-
NOW 的后繼的前驅的處理:
實際上,當且僅當 NOW 沒有前驅的時候它才會指向 START,其余情況均不變
-
NOW 的后繼的后繼的前驅的處理:
- 假定它存在,那么:
-
如果 NOW 無前驅:顯然應該是 NOW 的后繼
-
如果 NOW 有前驅:顯然應該是 NOW 的前驅
將上述三段整合為幾個三目套三目,即可。
代碼
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int Hen_hen_eaaaaa(233333);
struct Eat{
int Now,Nxt,Bef,Col;//位置、前驅、后繼
}eat[Hen_hen_eaaaaa],frt[Hen_hen_eaaaaa];
int n,cnt,STT;
bool NOW;//當前水果(用於建立不同塊
inline int R(){
int x=0,f=1;char c='c';
while(c>'9'||c<'0'){f=f*(c=='-'?-1:1);c=getchar();}
while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=R();
if(!n) return 0;
for(int i=1;i<=n;++i){frt[i].Col=R();frt[i].Bef=i-1;frt[i-1].Nxt=i;}
NOW=!frt[1].Col;frt[0].Nxt=1;
for(int i=1;i<=n;++i){
if(frt[i].Col!=NOW){
NOW=frt[i].Col;
eat[++cnt].Now=i;
eat[cnt].Bef=cnt-1;
eat[cnt-1].Nxt=cnt;
}
}
int N,NN,NNN;
while(frt[0].Nxt&&eat[0].Nxt){
N=eat[0].Nxt;
while(N){
printf("%d ",eat[N].Now);
NN=eat[N].Now;
frt[frt[NN].Bef].Nxt=frt[NN].Nxt;
frt[frt[NN].Nxt].Bef=frt[NN].Bef;
eat[N].Now=frt[NN].Nxt;
NNN=eat[N].Now;
if(((frt[NNN].Col!=frt[NN].Col)||(!NNN))&&((frt[eat[eat[N].Bef].Now].Col!=frt[NN].Col)||(!eat[N].Bef))){
eat[eat[N].Bef].Nxt=(eat[N].Bef?((eat[eat[N].Nxt].Nxt&&eat[N].Nxt)?eat[eat[N].Nxt].Nxt:0):eat[N].Nxt);
eat[eat[eat[N].Nxt].Nxt].Bef=((eat[N].Bef&&eat[eat[N].Nxt].Nxt&&eat[N].Nxt)?eat[N].Bef:eat[eat[eat[N].Nxt].Nxt].Bef);
eat[eat[N].Nxt].Bef=((eat[N].Bef||!eat[N].Nxt)?eat[eat[N].Nxt].Bef:0);
}//最難の合並操作
N=eat[N].Nxt;
}
printf("\n");
}
return 0;
}
