1. 程式人生 > >hdu 5929 Basic Data Structure 2016CCPC東北地區大學生程式設計競賽

hdu 5929 Basic Data Structure 2016CCPC東北地區大學生程式設計競賽

題目大意:

模擬一個棧,有四種操作:
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; } } }