Codeforces Raif Round 1 (Div. 1 + Div. 2) D

文章描述了一种名为D-BouncingBoomerangs的问题解决方法,涉及到使用栈和队列数据结构来安排物品的位置。对于每一列,根据物品的数量(0,1,2,或3),采取不同的策略进行放置。当无法找到合适的位置时,返回-1。最终将解决方案存储在向量中并输出。
摘要由CSDN通过智能技术生成

D - Bouncing Boomerangs

分析

一个stack用于存只有一个的物品的行的物品位置,一个queue用于存有两个物品的行的左边物品位置

(其实这两个容器用stack还是queue无所谓,只是这样易于区分)

先安排最后一列:0不放,1在[n][n]的位置放

然后从n-1列往前逐列安排,策略:

a[i]=0,continue。

a[i]=1,往上升一行(即 去到一个全新的行),放置,同时把这个物品的信息压入stack。

a[i]=2,因为每行最多放两个物品,所以去找之前只有一个物品的行物品,这个物品的行是tt,那么第i列放置位置为[tt][i]。把用过的物品从stack中弹出,同时把刚放置的物品位置压入queue。

a[i]=3,先找之前有两个物品的行左边物品,让回旋镖第三次碰撞到这个物品上。因为这个物品的行已经有两个物品,不能再添加物品,所以可以看作“废弃的行”,那既然如此,为什么不让这个行发挥一下“余热”,去作为另一个回旋镖的第三次碰撞单位呢?所以,全新的一行为row,左边物品列是yy,那么放置的两个物品位置为[row][i]、[row][yy]。把用过的左边物品从queue中弹出,把[row][i]压入queue。

还是a[i]=3,如果找不到有两个物品的行,还可以找有一个物品的行物品让回旋镖第三次碰撞到这个物品上。作用和使用方法跟上一段的左边物品相同,但因为这一行不是“废弃的行”,所以不是首选。这个物品作为第三次碰撞的物品后,的左边就不能再有物品,所以把物品信息从stack中弹出,把[row][i]压入queue。

在整个过程中,一旦发现stack或queue空了,导致没法安排当前元素,直接输出-1return。

用vector存答案,最后统一输出。

代码

#include<bits/stdc++.h>
#define ll long long
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int n,a[100005];
vector<pair<int, int> > v;
stack<pair<int, int> > s; //存只有一个的点行的点 
queue<pair<int, int> > q; //存有两个点行的左边那个点 
void solve(){
    cin>>n;
    rep(i,1,n){
        cin>>a[i];
    }
    if(a[n]>1){
        cout<<"-1\n"; return;
    }
    int temrow=0,flag;
    if(a[n]==1){
        v.push_back({n,n});
        temrow=n;
        s.push({n,n});
        flag=1;
    }
    for(int i=n-1;i>=1;i--){
        if(a[i]==0) continue;
        if(a[i]==2){
            flag=0;
            if(s.empty()){
                cout<<"-1\n";
                return;
            }
            pair<int,int> tt=s.top();
            s.pop();
            v.push_back({tt.first, i});
            q.push({tt.first, i});
        }
        if(a[i]==1){
            flag=1;
            if(temrow==0){
                v.push_back({n,i});
                temrow=n; 
                s.push({n,i});
                continue;
            }
            if(temrow>1){
                temrow--;  
                s.push({temrow,i});
                v.push_back({temrow,i}); 
                continue;
            }
            cout<<"-1\n"; return;
        }
        if(a[i]==3){
            if(temrow>1){
                temrow--;
                v.push_back({temrow,i});
                if(!q.empty()){
                    pair<int,int> tt=q.back();
                    q.pop();
                    v.push_back({temrow, tt.second});
                    q.push({temrow,i});
                } 
                else{
                    if(s.empty()){
                        cout<<"-1\n";return;
                    }
                    pair<int,int> tt=s.top();
                    s.pop();
                    v.push_back({temrow, tt.second});
                    q.push({temrow,i});
                }
                continue;
            }
            cout<<"-1\n"; return;
        }
    }
    
    if(v.empty()) {cout<<"0\n"; return;}
    
    cout<<v.size()<<"\n";
    rep(i,0,v.size()-1){
        cout<<v[i].first<<" "<<v[i].second<<"\n";
    }
} 
int main(){
    ios_base::sync_with_stdio(false); 
    cin.tie(0); 
    cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值