Educational Codeforces Round 120 (Rated for Div. 2) A - D
阿新 • • 發佈:2022-05-10
A - Construct a Rectangle
題意:
給你\(3\)個數\(l_1,l_2,l_3\),問能否分割其中一個數,使得四個陣列成一個矩形,特殊地,正方形也是矩形。
- 判段一下是否有兩數之和等於另一數後者是否有兩數相等且第三個數為偶數
#include <bits/stdc++.h> using namespace std; void solve() { int l1,l2,l3; cin >> l1 >> l2 >> l3; if(l1 + l2 == l3 || l1 + l3 == l2 || l2 + l3 == l1) { cout << "YES\n"; } else if(l1 == l2 && l3 % 2 == 0|| l1 == l3 && l2 % 2 == 0|| l2 == l3 && l1 % 2 == 0) { cout << "YES\n"; } else { cout << "NO\n"; } } int main() { int T; cin >> T; while(T --) { solve(); } }
B - Berland Music
題意:
給定排列\(p\)和一個二進位制\(01\)串\(s\),構造一個排列\(q\)使得二進位制串中\(\forall s_i = 1,s_j = 0,q_i > q_j\),並且要求\(\sum_{i = 1}^n|q_i - p_i|\)最小。
- 貪心
- 首先根據\(01\)串把\(1 - n\)分為兩大類,小的分配給串中為\(0\)的位置,大的反之,對應的分配規則即按照原先\(p\)中大小關係分配給對應大小關係的\(q\)使得差儘可能的小。
#include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; vector<int>p(n + 1),q(n + 1); for(int i = 1;i <= n;i ++) { cin >> p[i]; } vector<pair<int,int>>a1,a0; string s; cin >> s; for(int i = 0;i < s.size();i ++) { if(s[i] == '1') a1.push_back({p[i + 1],i + 1}); else a0.push_back({p[i + 1],i + 1}); } sort(a1.begin(),a1.end()); sort(a0.begin(),a0.end()); int pos = 0; for(auto i : a0) { q[i.second] = ++pos; }; for(auto i : a1) { q[i.second] = ++pos; } for(int i = 1;i <= n;i ++) { cout << q[i] << " \n"[i == n]; } } int main() { int T; cin >> T; while(T --) { solve(); } return 0; }
C - Set or Decrease
題意:
給定一個數列\(a\)和一個數\(k\)。每次操作你可以選擇如下兩種操作之一:
- 選擇一個位置\(i\),使得\(a_i = a_i + 1\)
- 選擇兩個位置\(i,j\),使得\(a_i = a_j\)
問需要最少的操作次數使得\(\sum a \le k\)
- 根據題目所給樣例我們也能貪心的想到,更優的方案是摁住數列中最小的數減一定次數後,再把數列中剩餘大的數一起減到當前最小數的值
- 將陣列排序後,維護一個字尾後,方便每次統計答案
- 二分操作次數,每次\(check\)時,因為\(k\)很大,我們不能列舉最小數減多少次,我們直接列舉字尾的幾個數變小,剩下的次數直接讓最小的\(a\)
- 注意列舉的邊界,因為我們預設用\(a_1\)進行減操作,所以只需列舉\(0 - n - 1\)的字尾和即可,其實也易得變\(a_1\)肯定不是最好的操作
- 複雜度\(O(nlogn)\)
#include <bits/stdc++.h>
using namespace std;
//1 1 1 2 2 3 6 6 8 10
void solve() {
int n; long long k;
cin >> n >> k;
vector<long long>a(n + 1),s(n + 2,0);
for(int i = 1;i <= n;i ++) cin >> a[i];
sort(a.begin() + 1,a.begin() + 1 + n);
for(int i = n;i >= 1;i --) s[i] = s[i + 1] + a[i];
if(s[1] <= k) {
cout << "0\n";
} else if(n == 1) {
cout << a[1] - k << '\n';
} else {
auto check = [&](long long x) {
for(int i = 0;i < n && i <= x;i ++) {//列舉把字尾的幾個數變掉 這麼寫不要帶n因為默認了第一個是用來減的 不過也易得 先減再變肯定比直接變好
long long t = a[1] - (x - i);
long long del = s[n - i + 1] - (t * i) + (x - i);
if(s[1] - k <= del)
return true;
}
return false;
};
long long l = 1,r = s[1] - k,ans;
while(l <= r) {
long long mid = l + r >> 1;
if(check(mid)) {
r = mid - 1; ans = mid;
} else {
l = mid + 1;
}
}
cout << ans << '\n';
}
}
int main() {
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
int T; cin >> T;
while(T --) {
solve();
}
return 0;
}