Atcoder Beginner Contest 270(ABC 270) A B C E题

A

传送门

A题你可以用把n,m转成二进制后,按题目模拟,但是,有更快捷的做法。

将n,m转为二进制后,你会发现,每个位有1为1,无一为0,这和逻辑或运算方法一模一样,

所以只要将n,m进行或运算就可以了。

#include<bits/stdc++.h>
using namespace std;
string s;
void init(){
    
}
signed main(){
    int n,m,k;
    cin >> n >> m;
    cout << (n | m) << endl;
    return 0;
}

B

传送门

这里我们分类讨论一下。

n表示x,z中最小的,m表示最最大的。

如果((n < y && y < 0)||  (m > y && y > 0))即,x,z都被y 与原点隔开了,输出-1

如果x,y不同号,直接输出x的绝对值,因为Takahashi可以直接走过去。

如果(y < x && x < 0) || (y > x && x > 0) ,即x的绝对值小于y的绝对值,Takahashi也可以直接走过去 。

剩余情况Takahashi就先拿锤子,再走到x就可以了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
string s;
void init(){
    
}
bool th(int a,int b){
    return ((a < 0 && b < 0) || (a > 0 && b > 0));
}
signed main(){
    int n,m,k;
    init();
    int x,y,z;
    cin >> x >> y >> z;
    n = max(x,z);
    m = min(x,z);
    if (n < y && y < 0) cout << -1 << endl;
    else if (m > y && y > 0) cout << -1 << endl;
    else{
        if (!th(x,y)) cout << abs(x) << endl;
        else{
            if ((y < x && x < 0) || (y > x && x > 0)) cout << abs(x) << endl;
            
            else{
                int step = 0;
                int now = z;
                step += abs(z);
                step += abs(x - z);
                cout << step << endl;
            }
            
        }
    }
    return 0;
}

C

传送门

这题是个经典的DFS,我们首先建一棵树,每棵树的边都是双向的,这里,我们利用DFS的可回溯来求答案。

我们需要一个 函数 DFS(x,fa)。

x 表示当前节点的编号,fa表示他的父亲。

DFS(x,fa)的返回值表示本路径是否可以从x到y。

其他东西见代码

写法一:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
void init(){
    
}
vector <int> G[N];
int n,s,t;
vector <int> ans;
bool DFS(int x,int fa){
    if (x == t){
        ans.push_back(x);
// 如果当前节点就是我们要找的终点,说明这条路可行。
        return true;
    }
    for (int i = 0 ; i < G[x].size() ; i ++){
        int v = G[x][i];
        if (v != fa && DFS(v,x)) {
// 递归的可回溯性,如果这个点的子孙是终点,那说明路径上一定有它。
            ans.push_back(x);
            return true;
        }
    }
    return false;
}
signed main(){
    init();
    cin >> n >> s >> t;
    for(int i = 1 ; i < n ; i ++) {
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    DFS(s , -1);
// 因为我们是从终点开始放入答案,所以要倒着输出结果,方法二则是优化了这个步骤。
    for (int i = ans.size() - 1 ; i >= 0 ; i --) cout << ans[i] << " ";
    return 0;
}

写法二:

因为上述做法是倒叙的,所以,我们为了优化一个vector的复杂度,从终点开始,搜起点。

搜到了就将它输出。省掉了倒着输出的这个步骤。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
void init(){
    
}
vector <int> G[N];
int n,s,t;
bool DFS(int x,int fa){
    if (x == t){
        cout << x << " ";
        return true;
    }
    for (int i = 0 ; i < G[x].size() ; i ++){
        int v = G[x][i];
        if (v != fa && DFS(v,x)) {
            cout << x << " ";
            return true;
        }
    }
    return false;
}
signed main(){
    init();
    cin >> n >> s >> t;
    for(int i = 1 ; i < n ; i ++) {
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    swap(s,t);
// swap(s,t)将s,t反了一下,s变成了终点,t变成了起点
    DFS(s,-1);
    return 0;
}

E

传送门

这题有多种做法,但是巨菜的本人只提供二分答案。

这里,我们把每个篮子想象成n根柱子,每个柱子高a[i],我们二分刀的高度,

把每个柱子从下到上切掉这段距离,如果小于这段就能取多少取多少,(问题的转化)

如果总和大于k就记录一下答案,然后不断减少,直至不能再减。

这样肯定会多砍。所以我们要求出多砍了多少根,把他们加回去,具体细节见代码。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
string s;
int a[N];
void init(){
    
}
int n,m,k;
bool check(int x){
    int cnt = 0 ;
    for(int i = 1 ; i <= n ;i ++) cnt += min(x,a[i]);
    return cnt >= k;
}
signed main(){
    init();
    cin >> n >> k;
    int l = 0 , r = -1e18;
    for (int i = 1 ; i <= n ;i ++) cin >> a[i], r = max(r , a[i]);
    int ans = 0;
    while (l <= r){
        int mid = l + r >> 1;
        if (check(mid)) {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
// 二分答案,ans是二分的结果。
    int sum = 0;
    for (int i = 1 ; i <= n ; i ++) {
        sum += min(a[i] , ans);
    }
    int t = sum - k;
    for (int i = n ; i >= 1 && t > 0 ; i --){
        if (a[i] <= ans) continue;
// 思考一下,你会发现如果a[i] <= ans,那么ans对答案都没有多贡献1,所以a[i] <= ans时,不用加。
        a[i] ++;
        t --;
    }
    for (int i = 1 ; i <= n ; i ++){
        a[i] -= min(a[i] , ans);
// 算出结果。
        cout << a[i] << " ";
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值