The 18-th Beihang University Collegiate Programming Contest (BCPC 2023) - Final

https://codeforces.com/gym/104883

A

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;


i32 main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    i64 n, sum = 0;
    cin >> n;
    for(int i = 1, x; i <= n ; i ++)
        cin >> x, sum += x;
    cout << max(0ll, sum);
    return 0;
}

B

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int long long

using vi = vector<int>;


i32 main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vi a(n);
    for(auto &i : a) cin >> i;
    
    int m;
    cin >> m;
    vi b(m);
    for(auto &i : b) cin >> i;

    sort(b.begin(), b.end());
    for(int i = 1; i <= m; i ++) b[i] += b[i-1];
    for( int i = 0; i < n ; i ++)
        cout << upper_bound(b.begin(), b.end(), a[i]) - b.begin() << " ";
    return 0;
}

C

先说\(b\le a\)怎么满足,必定是有一个前缀和\(a\)完全相同,然后前缀后第一位\(a\)一定是\(1\)\(b\)\(0\),再往后就可以随便取值了。这的话前缀内的异或值为 0,之后的异或值全部为\(1\)。所以可以二分最长的前缀,然后后缀的每一位都取反即可。这样的话异或后\(1\)的数量可能大于\(x\),我们在后缀中从高位开始,尽可能的插入\(1\)就好了。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int long long

using vi = vector<int>;


i32 main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string s;
    int x;
    cin >> s >> x;
    if(x == 0) {
        cout << s;
        return 0;
    }else if(s.size() < x) {
        cout << -1;
        return 0;
    }

    vi pos;
    for(int i = 0; i < s.size(); i ++)
        if(s[i] == '1') pos.push_back(i);
    if(pos.empty()) {
        if(x > 0) cout << -1;
        else cout << 0;
        return 0;
    }
    int l = 0, r = pos.size() - 1, m = -1;

    auto check = [=](int a){
        int c = s.size() - pos[a] - 1;
        return c >= x - 1;
    };

    while (l <= r ) {
        int mid = (l + r) / 2;
        if(check(mid)) l = mid + 1, m = mid;
        else r = mid - 1;
    }

    string res;
    if(pos[m] != 0) res += s.substr(0, pos[m]) + "0";

    string ans = s.substr(pos[m] + 1);
    for(auto &i: ans) {
        if(i == '0') i = '1';
        else i = '0';
    }
    for(int i = 0, cnt = ans.size() - x + 1; cnt > 0 and i < ans.size(); i ++ )
        if(ans[i] == '0') ans[i] = '1', cnt --;
    res += ans;
    for(int i = 0; i < res.size(); i ++ ){
        if(res[i] == '0') continue;
        cout << res.substr(i);
        return 0;
    }
    cout << 0;
    return 0;
}

D

一开始构造一个菊花图,然后对于每个点尽可能的插到最深的点上。

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;


signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, d;
    cin >> n >> d;
    if (d < (n - 1) or d > n * (n - 1) / 2) {
        cout << "NO\n";
        return 0;
    }
    vi fa(n + 1);
    fa[2] = 1;
    int sum = n - 1;
    int top = 1;
    vi dep;
    dep.push_back(1), dep.push_back(2);
    for (int i = 3, l, r, res, mid; i <= n; i++) {
        l = 0, r = top, res = -1;
        while (l <= r) {
            mid = (l + r) / 2;
            if (sum + mid <= d) res = mid, l = mid + 1;
            else r = mid - 1;
        }
        sum += res, fa[i] = dep[res];
        if (res == top) top++, dep.push_back(i);
    }
    cout << "YES\n";
    for( int i = 2 ; i <= n ; i ++ )
        cout << fa[i] << " " << i << "\n";
    cout << "1\n";
    return 0;
}

E

每次贪心的合并最小的两个或三个(相邻且相同的只有三个)是最优解。用set维护所有的区间的值和区间的大小即可。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int long long

using vi = vector<int>;

void solve() {
    int n;
    cin >> n;
    set<array<int,3>> q;
    for(int i = 1, x; i <= n; i ++)
        cin >> x, q.insert({x, i, i});
    while(not q.empty()) {
        auto [x, l, r] = *q.begin();
        q.erase(q.begin());
        if(q.empty()){
            cout << "Yes\n";
            return;
        }
        if(q.begin()->at(0) == x and q.begin()->at(1) == r + 1 ){
            r = q.begin()->at(2), q.erase(q.begin());
            if(not q.empty() and q.begin()->at(0) == x and q.begin()->at(1) == r + 1){
                if(q.size() == 1) {
                    r = q.begin()->at(2) , q.erase(q.begin());
                }else{
                    auto it = *next(q.begin());
                    if(it[0] != x or q.begin()->at(2) + 1 != it[1]) 
                        r = q.begin()->at(2), q.erase(q.begin());   
                }
            }
            q.insert({x + 1, l, r});
        }else{
            cout << "No\n";
            return ;
        }
    }
    return;
}

i32 main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for(cin >> TC; TC; TC --) solve();
    return 0;
}

F

可以根据二分的过程,确定每个位置上数字的取值范围,我们把范围从小到大排序,然后对于每个范围,我们贪心的选择打满足这个范围的最大值。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int long long

using vi = vector<int>;

void solve() {
    int n, m;
    cin >> n >> m;
    vi p(n + 1, 1), q(n + 1, n + 1);// p[i] <= a[i] < q[i]
    for(int x, y, l, r, mid; m; m --){
        cin >> x >> y, l = 1, r = n;
        while(l < r) {
            int mid = (l + r) / 2;
            if (mid < y) q[mid] = min(q[mid], x), l = mid + 1;
            else p[mid] = max(p[mid], x), r = mid;
        }
    }
    for(int i = 1; i <= n ; i ++ ){
        if(p[i] < q[i]) continue;
        cout << "-1\n";
        return;
    }
    vi res(n+1);
    set<int> s;
    for (int i = 1; i <= n; i ++ ) s.insert(i);
    vi a(n+1);
    iota(a.begin(), a.end(), 0);

    sort(a.begin() + 1, a.end(), [&](int i, int j){
        if(q[i] - p[i] != q[j] - p[j]) return q[i] - p[i] < q[j] - p[j];
        return p[i] > p[j];
    });
    for( int x = 1, i; x <= n; x ++) {
        i = a[x];
        auto it = (s.lower_bound(q[i]));
        if(it == s.begin()) {
            cout << "-1\n";
            return;
        }
        it = prev(it);
        if(*it >= p[i]) res[i] = *it, s.erase(it);
        else {
            cout << "-1\n";
            return;
        }
    }
    for(int i = 1; i <= n ; i ++) cout << res[i] << " \n"[i == n];
    return;
}

i32 main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for(cin >> TC; TC; TC --) solve();
    return 0;
}
posted @ 2024-04-22 14:50  PHarr  阅读(59)  评论(0编辑  收藏  举报