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;
}