Educational Codeforces Round 124 (Rated for Div. 2)ABCD题解

A. Playoff

传送门
在这里插入图片描述
题目大意:输入一个整数n,就有2n个人进行分组比赛,第一轮:12一组,34一组,…,2n-1和2n一组,当一组内编号连续则胜者为编号小的那个,否则胜者为编号高的那个。
解题思路:很明显最后胜者始终为最大的奇数即2n-1

输入样例

2
3
1

输出样例

7
1
#include <iostream>

using namespace std;
typedef long long ll;
const int N = 31;
ll a[N];
int main()
{
    int t;
    cin >> t;
    a[0] = 1;
    for(int i = 1 ; i < N ; i++){
        a[i] = a[i - 1] * 2;
    }
    while(t--){
        int n;
        cin >> n;
        cout << a[n] - 1 << endl;
    }
    return 0;
}

B. Prove Him Wrong

传送门
在这里插入图片描述
输入样例

3
2
512
3

输入样例

YES
1 337
NO
YES
31 4 159

在这里插入图片描述
题目大意:对于一个长度为n的数组a,一定能找到两个下标i,j,令a[i]=a[j]=|a[i]-a[j]|,数组a的总和会减少,我们要证明这个结论是错误的。输入一个n为数组的长度,如果有一个数组a,a中的元素不能大于1e9,进行任意这样的操作最后数组a的总和增加或不变,就输出数组a,否则输出NO。
解题思路:将题目的意思转换为不等式即我们要找到一个a[i],a[j]使得:
a[i]+a[j] <= 2 * |a[i]-a[j]| =>
a[i]+a[j] <= 2 * a[j] - 2 * a[i] =>
3a[i] <= a[j] =>
a[i] <= 1/3 * a[j]
所以第二个数只要是第一个数的3倍及以上,那么二者差值的2倍一定大于二者之和,那么我们就可以得到一个序列1 3 9 27 … 直到大于1e9,如果遇到第一个a[m] > 1e9那么输入的n如果大于等于m就输出No,否则输出Yes,所以我们需要先预处理一下

#include <iostream>
using namespace std;
const int N = 1002;
typedef long long ll;
ll a[N];
int main()
{
    int t;
    cin >> t;
    a[1] = 1;
    int flag = 0;
    for(int i = 2 ; i < 1002 ; i++ ){
        if(!flag){
            a[i] = a[i - 1] * 3;
        }
        if(a[i] * 3 > 1e9 && !flag){
            flag = i;
        }
    }
    while(t--){
        int n;
        cin >> n;
        if(n > flag){
            cout << "NO";
        }else{
            cout << "YES" << endl;
            for(int i = 1 ; i <= n ; i++){
                cout << a[i] << " ";
            }
        }
        cout << endl;
    }
    return 0;
}

C. Fault-tolerant Network

传送门
在这里插入图片描述
输入样例

2
3
1 10 1
20 4 25
4
1 1 1 1
1000000000 1000000000 1000000000 1000000000

输出样例

31
1999999998

题目大意:有两排电脑,每排电脑的个数为n,每排的电脑网络都是互通的(假设第一排的电脑为数组a,第二排为数组b),如a1连接a2,a2连接a3,…,an-1连接an,b也是一样。但是ab互不连通,现在需要你将a和b连接起来,每次连接都会花掉|ai-bj|,并保证a和b任意一台电脑挂掉了,a和b的网络连接不会断也不会出现某台电脑被孤立同时花费最小。

解题思路:通过分析我们可以知道,边界电脑a1,an,b1,bn必须被连接,如果a1没有被连接,那么假设a2挂掉了,a1就会成为孤立的点,同时我们也只需要让这四个点被连接,这样无论哪个的电脑挂掉都能保证两排电脑的每两个都能互通。可以抽象成一个矩形,如果有条边断掉,也还是一根线,不会断成两根线。
那么如何保证这四个点都被连接并且花费最小呢,这就需要枚举了。首先对于a1,有三种连接情况:b1,bn,bi:min(|a1-bi|)(i>1&i<n),b1、bn、an的情况也一样。我们只需要将这些情况枚举,找到最小的花费即可。

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6;
#define Inf 1e9
typedef long long ll;
bool vis[N];
ll ans;
int cal(vector<ll> &v,int cur){ //寻找与该数组元素的最小差值
    ll res = 1e9;
    int pos;
    for(int i = 0 ; i < v.size() ; i++){
        if(res > abs(v[i] - cur)){
            res = abs(v[i] - cur);
            pos = i;
        }
    }
    return pos;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        vector<ll>a,b;
        ans = 10ll * Inf;
        int n;
        scanf("%d",&n);
        ll x;
        for(int i = 1 ; i <= n ; i++){
            scanf("%lld",&x);
            a.push_back(x);
        }
        for(int i = 1 ; i <= n ; i++){
            scanf("%lld",&x);
            b.push_back(x);
        }
        vector<int> pos1 = {0, cal(b,a[0]), n-1};
        vector<int> pos2 = {0, cal(b,a[n-1]), n-1};
        for(auto i : pos1){
            for(auto j : pos2){
                ll res = abs(a[0] - b[i]) + abs(a[n - 1] - b[j]);
                if(i > 0 && j > 0){ // 如果a0没有连接b0
                    res += abs(b[0] -a[cal(a,b[0])]);
                }
                if(i < n -1 && j < n - 1){ // 如果an-1没有连接bn-1
                    res += abs(b[n - 1] - a[cal(a,b[n - 1])]);
                }
                ans = min(ans,res);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D. Nearest Excluded Points

传送门
在这里插入图片描述
输入样例1

6
2 2
1 2
2 1
3 2
2 3
5 5

输出样例1

1 1
1 1
2 0
3 1
2 4
5 4

输入样例2

8
4 4
2 4
2 2
2 3
1 4
4 2
1 3
3 3

输出样例2

8
4 4
2 4
2 2
2 3
1 4
4 2
1 3
3 3

题目大意:给你一个点集,对于每个点输出不在点集内并且距离该点曼哈顿距离最近的点,曼哈顿距离distance = |x1-x2|+|y1-y2|
解题思路:采用bfs,首先遍历点集,对于一个点(x,y),曼哈顿距离最近为1,那么就遍历该点四个方向的点,如果找到一个点不在点集内就将(x,y)加入队列然后break。如果一个点四个方向的点都在点集内,那么与它曼哈顿距离最近的就是它四个方向中的点中曼哈顿距离最近的,可能有点绕,你可以想象假设一个点,他四个方向的点都在点集内,那么曼哈顿距离最近的点就变成外围点中曼哈顿距离最近的点,那么这个曼哈顿距离就变成2,因为曼哈顿距离为1的点都不能取。最后遍历整个队列,相当于这个队列的初始值就是整个图中最外围的点,那么里面的点就迭代更新为外围曼哈顿距离最近的点的答案。里面的点的答案就是外围点的答案。不停地迭代,最终每个点曼哈顿距离最近且不再点集内的答案就出来了。

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
const int N = 1e6 + 100;
vector<int> g[N];
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
typedef pair<int,int> PII;
int main()
{
    int n;
    cin >> n;
    vector<PII> a(n);
    for(auto &[x,y] : a){
        cin >> x >> y;
    }
    set<PII> st(a.begin(),a.end());
    map<PII,PII> ans;
    queue<PII> q;
    for(auto [x,y] : a){
        for(int i = 0 ; i <4 ; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(st.count({nx,ny})){
                continue;
            }
            ans[{x,y}] = {nx,ny};
            q.push({x,y});
            break;
        }
    }
    while(!q.empty()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for(int i = 0 ; i < 4 ; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(!st.count({nx,ny}) || ans.count({nx,ny})){ //如果该点不是点集内的点或者已经找到该点的答案就不加入该点
                continue;
            }
            ans[{nx,ny}] = ans[{x,y}];
            q.push({nx,ny});
        }
    }
    for(auto [x,y] : a){
        auto i = ans[{x,y}];
        cout << i.first << " " << i.second << endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值