HDU5929 Basic Data Structure,ccpc,模擬雙端佇列(兩倍大的陣列從中間開始向兩旁拓展)
阿新 • • 發佈:2019-01-04
1
做題時:容易看出規律,最後一個0的後面的1的個數的奇偶性決定了輸出結果,第一次超時後,想到應該記錄最後一個0的位置即可,於是想用陣列儲存0的位置(太麻煩,應該用佇列或者陣列模擬的佇列),同時依然用雙端佇列模擬全部1和0的操作,從而導致一直超時。
重現賽後:看完題解後,領悟到模擬並不是單純地將所有過程全部死板的模擬一遍,我們在抓住問題的本質(規律)時,應該去繁就簡,只模擬需要的部分(去掉無效的以及重複的)。而在這個題中,關鍵是0的位置,而不是整體的所有的操作,所以只需要用雙端佇列維護0的位置即可,下面第一個程式另外用陣列模擬的雙端佇列進行了整體的操作更加容易理解一些,不過耗費的空間多了1000+kb,第二個程式則只維護了0的位置,用一個l、r記錄整體操作後的整體(0和1)個數。兩者速度相差不大,stl的deque的速度比用陣列模擬的速度並不會有明顯的慢,反倒是發現,判斷後的輸出語句與直接輸出語句、要比printf比cout的速度差更大,見code。
另外,注意三個特判,尤其是最後一個,0的上面是否還有數的判斷。
2
程式一:
程式二:<div></div><div>#include <iostream> #include <queue> #include <stdio.h></div><div>using namespace std; const int maxn=400100; int number[maxn]; deque<int> deq; int dir=1; int l,r; int cnt=0; void Push(){ int x; scanf("%d",&x); if(dir){ number[r]=x; if(!x) deq.push_back(r); r++; } else{ number[l]=x; if(!x) deq.push_front(l); l--; } cnt++; } void Pop(){ if(dir){ r--; if(number[r]^1) deq.pop_back(); } else{ l++; if(number[l]^1) deq.pop_front(); } cnt--; } void Query(){ int res; if(cnt==0){ cout<<"Invalid."<<endl; return ; } /*//已經被包含在下面了 if(cnt==1){ cout<<number[r-1]<<endl; } */ if(deq.empty()){ //cout<<"Note: deq.empty."<<endl; res=cnt; } else if(dir){ res=deq.front()==r-1?cnt-1:deq.front()-l; } else{ res=deq.back()==l+1?cnt-1:r-deq.back(); } printf("%d\n",res&1);//超級快 //比if(res%2==0)cout<<"..."<<endl;else... 快1000ms //比if(res&1) cout<<"1"<<endl;else cout<<"0"<<endl; 也快1000ms ///so,需要判斷的分支語句,要比printf更耗時間! } int main() { //freopen("out.txt","w",stdout); int tt; scanf("%d",&tt); int n; char com[20]; for(int kk=1;kk<=tt;kk++){ scanf("%d",&n); dir=1; cnt=0; r=200001; l=200000; deq.clear(); printf("Case #%d:\n",kk); for(int i=1;i<=n;i++){ scanf("%s",com); if(com[2]=='S'){ Push(); } else if(com[2]=='P'){ Pop(); } else if(com[2]=='V'){ dir^=1; }else{ Query(); } } } return 0; } </div>
#include <iostream> #include <stdio.h> using namespace std; const int maxn=400100; int number[maxn]; int l,r; int pos_l,pos_r;//the pos of 0 or 1. int cnt; int dir; void Push(){ int x; scanf("%d",&x); if(dir){ if(!x) number[r++]=pos_r++; else pos_r++; } else{ if(!x) number[l--]=pos_l--; else pos_l--; } cnt++; } void Pop(){ if(dir){ if(number[r-1]==pos_r-1){ r--; } pos_r--; } else{ if(number[l+1]==pos_l+1){ l++; } pos_l++; } cnt--; } void Query(){ int res; if(pos_l+1==pos_r){ cout<<"Invalid."<<endl; return; } else if(l+1==r){ res=pos_r-pos_l+1; } else if(dir){ res=number[l+1]-(pos_l+1); if((pos_r-1)>number[l+1]) res++; //res=number[l+1]==pos_r-1?cnt-1:number[l+1]-pos_l;① } else{ res=(pos_r-1)-number[r-1]; if(number[r-1]>(pos_l+1)) res++; //res=number[r-1]=pos_l+1?cnt-1:pos_r-number[r-1];②,不懂①和②分別替換上面兩句時,就會WA } printf("%d\n",res&1); } void test(){ int t1=0; int t2=4; int a[4]; a[t1++]=t2++; cout<<a[t1-1]<<endl; cout<<t1<<" "<<t2<<endl; } int main() { int kase; scanf("%d",&kase); for(int kk=1;kk<=kase;kk++){ int n; scanf("%d",&n); dir=1; r=200001; l=r-1; pos_r=r; pos_l=l; cnt=0; char com[20]; printf("Case #%d:\n",kk); for(int i=1;i<=n;i++){ scanf("%s",com); if(com[2]=='S'){ Push(); } else if(com[2]=='P'){ Pop(); } else if(com[2]=='V'){ dir^=1; } else{ Query(); } } } return 0; }