hdu 5929 Basic Data Structure 2016CCPC东北地区大学生程序设计竞赛

http://acm.hdu.edu.cn/showproblem.php?pid=5929

题目大意:

模拟一个栈,有四种操作:
PUSH x:往栈里压入x
POP:丢掉栈顶元素
REVERSE:把栈翻转过来
QUERY:从栈顶到栈底求nand(与非)

其中0 nand 0=1,1 nand 0=1,0 nand 1=1,1 nand 1=0.
输出每次的query结果,如果栈是空的输出Invalid.
题目分析:

栈长度最大为20w,又是双端的,所以用40w长的数组和两个指针模拟很容易实现前三个操作。
关键就是第四个。一开始不小心看成了异或,结果wa了一发,然后又想的是用线段树维护区间的nand值,然后写了几个数发现这个运算不满足结合律,也就是栈顶和栈底反过来的值都是不一样的~~

看了题解明白了,本题抓住的是任何东西nand 0都为1这一个性质,所以只需要用一个TreeSet(C++里就是set)来维护最左边和最右边的0就可以了,每次查询的时候,先读出离栈顶最远的那个0,然后看看0顶上有没有东西,如果有东西,不管是什么,这一段值都为1,如果没有就为0,那么就剩下了1串(因为前面一团东西nand 0就是1)求nand,显然只跟1的奇偶有关系。这里还有个坑导致wa了一发,就是0顶上没东西的时候,就只需要看0下面1的个数,而不是+1。

然后还有一个问题就是那个set的end()返回的迭代器是最大值后面的那个。。。。这块又wa了一发。

//source:2016CCPC东北地区大学生程序设计竞赛 - 重现赛
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
int t,n,x,ans,cnt;
int q[400010];
char op[10];
set<int> s;
int main() {
  //IN("5929.in");
  scanf("%d",&t);
  int ca=1;
  while(t--) {
    printf("Case #%d:\n", ca++);
    scanf("%d",&n);
    int l=200005,r=200006;//双端对列从中点开始
    s.clear();
    bool d=0;//0 for left,1 for right
    while(n--) {
      scanf("%s",op);
      if(op[0]=='P' && op[1]=='U') { //PUSH x
        scanf("%d",&x);
        if(d==0) {
          q[l]=x;
          if(x==0)
            s.insert(l);
          l--;
        }
        else {
          q[r]=x;
          if(x==0)
            s.insert(r);
          r++;
        }
      }
      else if(op[0]=='P' && op[1]=='O') { //POP
        if(d==0) {
          if(q[l+1]==0)
            s.erase(l+1);
          l++;
        }
        else {
          if(q[r-1]==0)
            s.erase(r-1);
          r--;
        }
      }
      else if(op[0]=='Q') { //QUERY
        if(r-l<=1)
          printf("Invalid.\n");
        else {
          if(s.empty())
            printf("%d\n", (r-l+1)&1);
          else {
            set<int>::iterator i = s.end();
            i--;
           //printf("Debug: begin=%d,end=%d,l=%d,r=%d,d=%d\n",*s.begin(),*i,l,r,d);
            if(d==0) {
              if(*i-l>1)
                printf("%d\n",(r-*i)&1);
              else
                printf("%d\n", (r-*i+1)&1);
            }
            else {
              if(r-*s.begin()>1)
                printf("%d\n",(*s.begin()-l)&1);
              else
                printf("%d\n",(*s.begin()-1-l)&1);
            }
          }
        }
      }
      else //REVERSE
        d=!d;
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值