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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值