hdu5929 Basic Data Structure(模拟+双端队列)

题目

让你模拟栈,实现n(2<=n<=2e5)个操作,操作分四种

①PUSH 0/1 会将0或1放到栈顶

②POP 弹出栈顶元素,保证不会对空栈进行该操作

③REVERSE 对栈内元素顺序反转,12345变54321

④QUERY 询问从栈顶到栈底的与非值,如a1与非a2与非a3

(与非操作 0与非0==1 0与非1==1 1与非0==1 1与非1==0)

思路来源

https://blog.csdn.net/STILLxjy/article/details/53997549

题解

注意到前面不管是0还是1,与非后面的一个0就会变成1,所以我们需要记录最后一个0的位置

而栈会反转,所以变成模拟双端队列,没反转向后加,反转了向前加,这就需要记录第一个0的位置

而0是可以被pop掉的,所以不能只用两个下标当指针,得记录所有0的位置,

事实上,出现最后一个0后,后面只有两种情况,空或全是1①

而出现最后一个0前面也有两种情况,空或有元素②

然后也要考虑,没有最后一个0(即全是1)的情形③

0的位置比较重要,得分开记录,而连续的1顺序与非和逆序与非是一样的,所以只需记录数量,合并到一个值上即可

在代码中,分当前双端队列里有元素数为0,为1,为2,或大于2讨论较为方便

心得

心态炸了,就是这题让我前天训练赛爆零,谁让我一上来开大模拟

然后敲了两天才敲出来,WA了得有将近10发

主要一直不知道自己的代码有什么问题,

最后急中生智写了个弱化的数据生成.cpp一直随一直随强行对拍,

发现自己是读错题了……是从栈顶与非到栈底wtm

同时训练的时候爆零给我们的启示是,

大模拟写的不熟的话就疯狂if-else,管它什么精简美观……

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=4e5+50;
int t;
int l,r,a[maxn],emp,v;
int n;
char s[35];
int op;//开始是r 正向 
int TOP(int v)
{
	if(v)return r;
	else return l;
}
int PUSH(int v)
{
	if(v)return ++r;
	else return --l;
}
int POP(int v)
{
	if(v)return --r;
	else return ++l;
}
int SIZE()
{
	if(l==r)return !emp;
	else return r-l+1;
}
int main()
{
    //freopen("1.txt","r",stdin);
    //freopen("WA.txt","w",stdout);
	scanf("%d",&t);
	for(int cas=1;cas<=t;++cas)
	{
		memset(a,-1,sizeof a);
		l=r=2e5+5;op=1;emp=1;
		scanf("%d",&n);
		printf("Case #%d:\n",cas);
		for(int i=1;i<=n;++i)
		{
		scanf("%s",s);
		//注意答案是从栈顶与非到栈底 看临近栈底的0 WA 4h 
		if(s[0]=='Q')
		{
			int sz=SIZE();
			if(!sz)puts("Invalid."); 
			else if(sz==1)
			{
				if(a[TOP(!op)]==0)puts("0");
				else printf("%d\n",a[TOP(!op)]%2);
			}
			else if(sz==2) 
			{
				if(a[TOP(!op)]==0)puts("1");
				else printf("%d\n",a[TOP(!op)]%2);
			}
			else
			{
				if(a[TOP(!op)]==0)puts("1");
				else printf("%d\n",(a[TOP(!op)]+1)%2);//多了一个可以变1的0 
			}
		}
		else if(s[0]=='P')
		{
			if(s[1]=='U')
			{
				scanf("%d",&v);
				if(SIZE()==0)
				{
				 a[TOP(op)]=v;
				 emp=0;
			    }
				else if(a[TOP(op)]>=1&&v==1)a[TOP(op)]++;//连着的一压在一起 
				else a[PUSH(op)]=v;
			}
			else if(s[1]=='O')
			{
				if(SIZE()==0)continue;
				if(a[TOP(op)]>1)a[TOP(op)]--;
				else if(SIZE()==1)emp=1;//只有0或1 
				else POP(op);
			} 
		}
		else if(s[0]=='R')op=!op;
	    }
	}
	return 0;
}

生成数据

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,sz;
void solve(int x)
{
	if(x<=4)
	{
	 printf("PUSH %d\n",rand()%2);
	 sz++;
    }
	else if(x==5)printf("REVERSE\n");
	else if(x==6)
	{
		if(sz==0)solve(rand()%5);
		else
		{
			printf("POP\n");
			sz--; 
		} 
	}
	else if(x==7)printf("QUERY\n");
}
int main()
{
	freopen("1.txt","w",stdout);
    printf("%d\n",1);
	n=20;
	printf("%d\n",n);
	for(int i=1;i<=n;++i)
	solve(rand()%8);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值