Codeforces Round 905 (Div. 3)D~G2
E. Look Back
因为每次都是2,可以推出x<=y2^(n),转化成 x/y<=2^(n),求n直接取对数即可
注意:
1.答案很大要开LL
2.不要直接乘,会爆LL,直接利用原式即可,如果后面的大,就减去大多少的对数
3.记得向上取整
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
void bu_f() {
int n;
cin >> n;
vector<int> v(n);
for (auto& u : v)cin >> u;
LL ans = 0, r = 0;
for (int i = 1; i < n; i++) {
int t = ceil(log2(1.0 * v[i - 1] / v[i]));
r += t;
if (r < 0) {
r = 0;
}
ans += r;
}
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) {
bu_f();
}
return 0;
}
D. In Love
判断是否存在不相交的俩线段,可以考虑最左边和最右边的线段是否相交
那么可以利用multiset存储每个线段(因为它可以自动排序)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
void bu_f() {
int n;
cin >> n;
multiset<int> sl, sr;
while (n--) {
char c;
cin >> c;
if (c == '+') {
int l, r;
cin >> l >> r;
sl.insert(l);
sr.insert(r);
}
else {
int l, r;
cin>>l>>r;
sl.erase(sl.find(l));
sr.erase(sr.find(r));
}
if (sl.size() > 1&&sr.size()>1 && *sr.begin() < *prev(sl.end())) {
cout << "YES\n";
}
else {
cout << "NO\n";
}
}
}
int main() {
int t=1;
//cin >> t;
while (t--) {
bu_f();
}
return 0;
}
题意:寻找连续子数组,在子序列中唯一。
子序列:随机选取或者删除原序列的元素,剩余元素拼合
考虑:选择一个连续子序列,设al为该序列的最左端,如果在该序列的左侧有一个元素a_l,使得a_l==al,那么该序列不满足唯一(有子序列重复),同理对右侧也一样
思路:
1.寻找该元素最先出现的位置和最后出现的位置(保证唯一性)
2.累加求和
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
void bu_f() {
int n;
cin >> n;
vector<int> a(n+1);
map<int, int> first, last;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (!first.count(a[i])) first[a[i]] = i;
last[a[i]] = i;
}
LL num = 0,ans=0;//开LL
for (int i = 1; i <= n; i++) {
if (first[a[i]] == i) num++;
if (last[a[i]] == i) ans += num;
}
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) {
bu_f();
}
return 0;
}
G1. Dances (Easy version)
题意:选择在a,b数组中各删除一个数,随机排序使得a[i]<b[i],问最小操作次数
给定a的首元素为1
分析:如果删的越多,那么越可能满足,答案具有单调性,直接二分
对于每一个操作:删a中元素最大的,b中元素最小的
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
void bu_f() {
int n, m;
cin >> n >> m;
vector<int> a(n), b(n);
a[0] = 1;
for (int i = 1; i < n; i++) cin >> a[i];
for (auto& v : b) cin >> v;
sort(a.begin(), a.end());
sort(b.begin(), b.end());
int l = -1, r = n + 1;
auto check = [&](int k) {
for (int i = 0; i < n - k; i++) {
if (a[i] >= b[i + k]) return false;
}
return true;
};
while (l + 1 < r) {//二分删的次数
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid;
}
cout << r << '\n';
}
int main() {
int t;
cin >> t;
while (t--) {
bu_f();
}
return 0;
}
G2. Dances (Hard Version)
正着解怎么也想不出?那直接反向思考吧。
思路:
1.因为a1的值会变化,不好判断删多少,但是我们可以知道原数组可以保留多少。
2.记录一行(一共有m行,对于每一个不同的a1值进行划分)可以保留多少。又因为每一行除了a1不同其他都相同,所以*m
3.在考虑a1可以保留的情况
4.总的删除量减去保留的量,就是我们要求的答案了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
void bu_f() {
int n, m;
cin >> n >> m;
vector<int> a(n-1), b(n);
for (int& v : a) cin >> v;
for (int& v : b) cin >> v;
multiset<int> s;
for (auto v : b) s.insert(v);
LL ans = 0;
for (auto v : a) {
auto it = s.upper_bound(v);
if (it!= s.end()) {
s.erase(it);
ans++;
}
}
ans *= m;//有m行
int mx = 0;
if (s.size()) mx = *prev(s.end());//首先要存在
ans += min(m, mx - 1);//有a1保留的情况
cout << 1LL * n * m - ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) {
bu_f();
}
return 0;
}
结束