HDU5929 Basic Data Structure,ccpc,模拟双端队列(两倍大的数组从中间开始向两旁拓展)

来源:互联网 发布:iphone8移动数据 编辑:程序博客网 时间:2024/04/23 19:34

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;}





0 0