Educational Codeforces Round 95 (Rated for Div. 2) A - D 解题报告
题目链接
A. Buying Torches
思路:
直接计算出需要的木棍,然后取除以 \((x -1)\)(向上取整),最后在加上 \(k\) 即可。
代码:
/*
* @Author : nonameless
* @Date : 2020-09-14 22:22:07
* @LastEditors : nonameless
* @LastEditTime : 2020-09-15 02:03:23
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define toStr(name) (#name)
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b,a % b):a;}
inline ll gcd(ll a, ll b) { return b ? gcd(b,a % b):a;}
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
template<class T>
inline void read(T &x){
x = 0;
int f = 1;
char c = getchar();
while(c < '0' || c > '9') if(c == '-') { f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
x = x * f;
}
template<class T>
inline void out(string a, T x){ cout << a << " = " << x << endl; }
int main(){
int t; read(t);
while(t --){
ll x, y, k; cin >> x >> y >> k;
ll all = k * y + k - 1;
ll tmp = all / (x - 1);
if(all % (x - 1)) tmp ++;
tmp += k;
cout << tmp << endl;
}
return 0;
}
B. Negative Prefixes
思路 :
直接计算出和 \(sum\)
- \(sum < 0\) :说明 \(k = n\),直接输出原数组即可。
- \(sum \geq 0\) :说明第 \(n\) 位是 \(\geq 0\) 的,那么我们要 \(n - 1\) 位也尽量 \(\geq 0\),那么就要把可变动的数里最小的放在当前位(如果当前位是可变的),依次类推,直到 \(sum < 0\)。
注:其实就是把可改变的数拿来排序,然后从大到小依次填充。
代码:
/*
* @Author : nonameless
* @Date : 2020-09-14 23:01:26
* @LastEditors : nonameless
* @LastEditTime : 2020-09-15 02:10:22
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define toStr(name) (#name)
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b,a % b):a;}
inline ll gcd(ll a, ll b) { return b ? gcd(b,a % b):a;}
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
template<class T>
inline void read(T &x){
x = 0;
int f = 1;
char c = getchar();
while(c < '0' || c > '9') if(c == '-') { f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
x = x * f;
}
template<class T>
inline void out(string a, T x){ cout << a << " = " << x << endl; }
const int N = 110;
int a[N], vis[N], b[N];
int main(){
int t; read(t);
while(t --){
int n; read(n);
ll sum = 0;
int cnt = 0;
for(int i = 1; i <= n; i ++) read(a[i]);
for(int i = 1; i <= n; i ++) read(vis[i]);
for(int i = 1; i <= n; i ++) sum += a[i];
for(int i = 1; i <= n; i ++) if(vis[i] == 0) b[++cnt] = a[i];
sort(b + 1, b + cnt + 1);
int idx = 0;
if(sum < 0){
for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
puts("");
} else{
for(int i = n; i >= 1; i --){
if(sum < 0) break;
if(vis[i] == 1){
sum -= a[i];
continue;
} else{
a[i] = b[++idx];
sum -= a[i];
vis[i] = 1;
}
}
for(int i = 1; i <= n; i ++){
if(vis[i] == 0) a[i] = b[++idx];
printf("%d ", a[i]);
}
puts("");
}
}
return 0;
}
C. Mortal Kombat Tower
思路:
首先很容易想到的是:如果第一位是 \(1\),那么答案加一。
那么还有什么情况是一定要跳过 \(1\) 的呢?考虑:\(111\) 这种情况,我们最多打死两个怪物,那么朋友必须要面对一只 \(hard\) 的怪物,所以答案加一。
而对于其他情况:\(000, 001, 010, 011, 100, 101, 110\) ,我们的朋友都是可以避免 \(1\) 的。
所以只要统计下 \([2, n]\) 的区间内存在几个 \(111\) 即可,特判第一位。
代码:
/*
* @Author : nonameless
* @Date : 2020-09-14 23:28:28
* @LastEditors : nonameless
* @LastEditTime : 2020-09-14 23:38:37
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define toStr(name) (#name)
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b,a % b):a;}
inline ll gcd(ll a, ll b) { return b ? gcd(b,a % b):a;}
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
template<class T>
inline void read(T &x){
x = 0;
int f = 1;
char c = getchar();
while(c < '0' || c > '9') if(c == '-') { f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
x = x * f;
}
template<class T>
inline void out(string a, T x){ cout << a << " = " << x << endl; }
const int N = 2e5 + 10;
int a[N];
int main(){
int t; read(t);
while(t --){
int n; read(n);
for(int i = 1; i <= n; i ++) read(a[i]);
int ans = 0, cnt = 0;
if(a[1] == 1) ans ++;
for(int i = 2; i <= n; i ++){
if(a[i] == 1) cnt ++;
else cnt = 0;
if(cnt == 3) {
ans ++;
cnt = 0;
}
}
cout << ans << endl;
}
return 0;
}
D. Trash Problem
思路:
可以向天再借五百年就好了
显然最后合并的两堆的距离最远。
设:\(a, b, c, d\),\((a:最左边的,b:合并完的某一堆,c:合并完的某一堆,d:最右边的)\)
那么 \(ans = b - a + d - c = d - a - (c - b)\)。
即最右边的减去最左边的,再减去相邻距离最远的。
那么用两个 \(set\) 来维护信息,\(s_1\) 维护当前的所有坐标,\(s_2\) 维护相邻两堆的距离。
对于每次插入或删除的数,找出其在 \(s_1\) 的前驱和后继,然后更新 \(s_2\) 即可。
注:
- \(s_2\) 必须是一个 \(multiset\)
- 找前驱和后继注意处理边界
代码:
/*
* @Author : nonameless
* @Date : 2020-09-15 00:13:17
* @LastEditors : nonameless
* @LastEditTime : 2020-09-15 01:58:19
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define toStr(name) (#name)
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b,a % b):a;}
inline ll gcd(ll a, ll b) { return b ? gcd(b,a % b):a;}
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
template<class T>
inline void read(T &x){
x = 0;
int f = 1;
char c = getchar();
while(c < '0' || c > '9') if(c == '-') { f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
x = x * f;
}
template<class T>
inline void out(string a, T x){ cout << a << " = " << x << endl; }
multiset<ll> s1, s2;
int main(){
int n, q; read(n); read(q);
auto add = [&](ll x){
auto it = s1.lower_bound(x);
if(it != s1.end()) s2.insert(*it - x);
if(it != s1.begin()) s2.insert(x - *prev(it));
if(it != s1.end() && it != s1.begin()) s2.erase(s2.find(*it - *prev(it)));
s1.insert(x);
};
auto del = [&](ll x){
s1.erase(x);
auto it = s1.lower_bound(x);
if(it != s1.end()) s2.erase(s2.find(*it - x));
if(it != s1.begin()) s2.erase(s2.find(x - *prev(it)));
if(it != s1.end() && it != s1.begin()) s2.insert(*it - *prev(it));
};
auto calc = [&]() -> ll {
if(sz(s1) <= 2) return 0;
return *prev(s1.end()) - *s1.begin() - *prev(s2.end());
};
for(int i = 1; i <= n; i ++){
ll x; read(x);
add(x);
//printf("sz(s2) = %d\n", sz(s2));
}
printf("%lld\n", calc());
while(q --){
int op; read(op);
ll x; read(x);
if(op == 1) add(x);
else del(x);
printf("%lld\n", calc());
}
return 0;
}