Atcoder Beginner Contest 294

A - Filter

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        if(x%2==0)cout<<x<<" ";
     }
    return 0;
}

B - ASCII Art

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=110;
int a[N][N];
int main()
{
    int h,w;
    cin>>h>>w;
    for(int i=1;i<=h;i++){
        for(int j=1;j<=w;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=h;i++){
        for(int j=1;j<=w;j++){
            if(a[i][j]==0) cout<<'.';
            else{
                printf("%c",'A'+a[i][j]-1);
            }
        }
        cout<<endl;
    }
    return 0;
}

C - Merge Sequences

大致题意就是对于A的每一个数,输出它们在所有数中(A和B的所有数)是第几小的数,对于B的每一个数,输出它们在所有数中是第几小的数

可以用两个指针分别遍历A和B中的每个数,然后两两比较,小的那个数就可以给它标记是第几小的数,双指针要注意边界问题,之前也做过类似的题目,经常搞不清边界,在这时就可以

用样例来试,发现如果A或B一边全部标记完了,那么剩下的就需要全部依次标记,可以将a[n+1]和b[m+1]初始化为超级大的数,这样的话,一边全部标记好之后,就可以把剩下的数依次标记了

注意while(l<=n||r<=m)用或而不是且

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int idxa[N],idxb[N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    a[n+1]=1e9+10;
    for(int i=1;i<=m;i++) cin>>b[i];
    b[m+1]=1e9+10;
    int l=1,r=1;
    int idx=1;
    while(l<=n||r<=m){
        if(a[l]<b[r]){
            idxa[l]=idx;
            l++;
            idx++;
        }
        else if(a[l]>b[r]){
            idxb[r]=idx;
            r++;
            idx++;
        }
    }
    for(int i=1;i<=n;i++) cout<<idxa[i]<<" ";
    cout<<endl;
    for(int i=1;i<=m;i++) cout<<idxb[i]<<" ";
    cout<<endl; 
    return 0;
}

D - Bank 

 

超时代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
const int N=5e5+10;
bool flag[N];//表示是否被呼叫过 
set<int>s;
int main()
{
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++) s.insert(i);
    while(q--){
        int op;
        cin>>op;
        if(op==1){
            for(auto v:s){
                if(!flag[v]){
                    flag[v]=true;
                    break;
                }
            }
        }
        else if(op==2){
            int x;
            cin>>x;
            s.erase(x);
        }
        else{
            for(auto v:s){
                if(flag){
                    cout<<v<<endl;
                    break;
                }
            }
        }
    } 
    return 0;
}

实际上根本没必要用flag标记是否被呼叫过,如果是第一次被呼叫,那么直接将其放入set中,set中的就表示被呼叫过但没来的人,如果呼叫过然后来了的人就从set中删去

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
set<int>s;
int main()
{
    int n,q;
    cin>>n>>q;
    int idx=1;
    while(q--){
        int op;
        cin>>op;
        if(op==1){
            s.insert(idx);//表示被呼叫过但没来
            idx++;
        }
        else if(op==2){
            int x;
            cin>>x;
            s.erase(x);//被呼叫过然后来了的
        }
        else{
            cout<<*s.begin()<<endl;
        }
    }
    return 0;
}

E - 2xN Grid

大致题意是有一个行为2列为L的矩阵

这样输入:输入N1对数字(x,y),表示数字x有y个,依次填入第一行

同理,输入N2对数字(x,y),表示数字x有y个,依次填入第二行

最终,同一列的两个数字相等算一组,问一共有几组

首先,不能一个一个的填,因为L可以达到1e12,一个一个的填必定超时,共有N1+N2对,可以一对一对填,这样不会超时

然后填完之后,可以利用双指针进行判断,同时枚举上一边和下一边

 

 代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
    int len,n1,n2;
    cin>>len>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n2;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    int l=0,r=0;
    int len1=a[0].second,len2=b[0].second;
    int res=0;
    if(a[0].first==b[0].first) res+=min(len1,len2);
    while(len1<=len||len2<=len){
        if(len1<=len2){
            l++;
            if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
            len1+=a[l].second;
        }
        else{
            r++;
            if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
            len2+=b[r].second;
        }
    }
    cout<<res<<endl;
    return 0;
}

进行改进:加上 

if(len1==len&&len2==len) break;//如果双指针用while加if和else的话,最后不要忘记再加一句以退出循环

 这样就没有RE了,此时还有点小错误,看来大方向是没问题的,只不过有一些小细节没有处理好,可能有特殊情况没有考虑到

代码如下: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
    int len,n1,n2;
    cin>>len>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n2;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    int l=0,r=0;
    int len1=a[0].second,len2=b[0].second;
    int res=0;
    if(a[0].first==b[0].first) res+=min(len1,len2);
    while(len1<=len||len2<=len){
        if(len1<=len2){
            l++;
            if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
            len1+=a[l].second;
        }
        else{
            r++;
            if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
            len2+=b[r].second;
        }
        if(len1==len&&len2==len) break;
    }
    cout<<res<<endl;
    return 0;
}

再进行改进,依旧是对边界的改进,改完之后又对了一个测试点 

if(len1<len) l++;
if(len2<len) r++;

 代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
    int len,n1,n2;
    cin>>len>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n2;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    int l=0,r=0;
    int len1=a[0].second,len2=b[0].second;
    int res=0;
    if(a[0].first==b[0].first) res+=min(len1,len2);
    while(len1<=len||len2<=len){
        if(len1<=len2){
            if(len1<len) l++;
            if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
            len1+=a[l].second;
        }
        else{
            if(len2<len) r++;
            if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
            len2+=b[r].second;
        }
        if(len1==len&&len2==len) break;
    }
    cout<<res<<endl;
    return 0;
}

此时样例错了一个,而且是样例二,第一行为1e10个1,第二行也为1e10个1

试了一下,发现res一开始+=1e10,然后len1变成了2e10,导致没有退出循环,后面res又加了,真是个巧合,这边可以避免len1变成2e10,即将res+=和len1+=都放到if(len1<len)里面

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
    int len,n1,n2;
    cin>>len>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n2;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    int l=0,r=0;
    int len1=a[0].second,len2=b[0].second;
    int res=0;
    if(a[0].first==b[0].first) res+=min(len1,len2);
    while(len1<=len||len2<=len){
        if(len1<=len2){
            if(len1<len) {
                l++;
                   if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
                len1+=a[l].second;
            }
        
        }
        else{
            if(len2<len) {
                r++;
                if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
                len2+=b[r].second;
            }
        }
        if(len1==len&&len2==len) break;
    }
    cout<<res<<endl;
    return 0;
}

或者将len1==len改为大于等于

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define int long long
using namespace std;
vector<pair<int,int>>a,b;
signed main()
{
    int len,n1,n2;
    cin>>len>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n2;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    int l=0,r=0;
    int len1=a[0].second,len2=b[0].second;
    int res=0;
    if(a[0].first==b[0].first) res+=min(len1,len2);
    while(len1<=len||len2<=len){
        if(len1<=len2){
            if(len1<len) l++;
            if(a[l].first==b[r].first) res+=min(a[l].second,len2-len1);
            len1+=a[l].second;
        }
        else{
            if(len2<len) r++;
            if(b[r].first==a[l].first) res+=min(b[r].second,len1-len2);
            len2+=b[r].second;
        }
        if(len1>=len&&len2>=len) break;
    }
    cout<<res<<endl;
    return 0;
}

 总的来说,一开始大致方向是对的,双指针主要难点在于处理边界问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值