题目描述
消除游戏需要 N 张大小为 1 ∼ N 的纸牌。
游戏开始时, N 张纸牌排成一行。对于某张纸牌,如果其牌面大小比右边相邻的纸牌小,那么这张纸牌将被消除。
游戏按照上述规则进行多轮消除,直到不存在满足条件的纸牌,游戏结束。
现在已知纸牌的初始排列顺序,请问消除游戏需要几轮结束,最后剩下的牌是什么。
输入
第一行一个正整数 T (T ≤ 10),表示测试数据的组数。
对每组测试数据,第一行一个整数 N(1 ≤ N ≤ 106),表示有 N 张纸牌。
第二行 N 个整数 ai(1 ≤ ai ≤ N, ∀i != j, ai != aj),表示从左到右纸牌的牌面大小。
输出
对于每组数据,输出两行。
第一行输出一个整数,表示消除游戏进行多少轮之后结束。
第二行按照从左到右的顺序,输出游戏结束时剩余纸牌的牌面大小。
样例输入
3 4 4 3 2 1 4 1 2 3 4 7 2 1 4 3 5 7 6
样例输出
0 4 3 2 1 1 4 2 7 6
找出所有能消除左边的数,对这里面每一个数而言,每一次操作或者能够删除一个数或者该数不再能够删除左边的数
利用堆栈或者递归函数
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
#define MAX 1000005
struct node{
int val,num,del;
};
int a[MAX];
int large[MAX];
int out[MAX];
int dfs(int l,int r){
if (l>=r) return 0;
stack<node>s;
while (!s.empty()){
s.pop();
}
int m=a[r],i=r-1,n=0,maxn;
while(i>=l&&!large[i]){
n++; i--;
}
if (i<l) return n;
node temp={m,++n,r-l+1};
s.push(temp);
m=a[i]; i--;
maxn=n; n=0;
while (i>=l)
{
if (large[i]==0)
{
if(a[i]<m&&n<maxn){
n++; i--;
}else{
temp=s.top(); s.pop();
n=temp.num; m=temp.val; maxn=temp.del;
}
}else{
if (a[i]<m&&n<maxn) {
n++;
if (n<maxn) {
node temps={m,n,maxn};
s.push(temps);
}
maxn=n; n=0; m=a[i--];
}else{
temp=s.top(); s.pop();
n=temp.num; m=temp.val; maxn=temp.del;
}
}
}
node temps={m,n,maxn};
s.push(temps);
while(!s.empty()){
temp=s.top(); s.pop();
}
return temp.num;
}
int main()
{
int t,n,m,k,ma,temp,r,p;
cin>>t;
while (t--)
{
memset(large,0,sizeof(large));
cin>>n>>a[1];
k=0; ma=0; p=0;a[0]=n+1;
for (int i=2;i<=n;i++)
{
cin>>a[i];
if (a[i]>a[i-1]){
large[i]=1;
p=1;
}
}
if (p==0)
{
cout<<0<<endl;
for (int i=1;i<n;i++)
cout<<a[i]<<" ";
cout<<a[n]<<endl;
continue;
}
m=a[n]; r=n; out[k++]=m;
for (int i=n-1;i>=0;i--)
{
if (a[i]>m){
out[k++]=a[i];
temp = dfs(i+1,r);
if(temp>ma) ma=temp;
r=i; m=a[i];
}
}
cout<<ma<<endl;
for (int i=k-2;i>0;i--)
cout<<out[i]<<" ";
cout<<out[0]<<endl;
}
return 0;
}