Educational Codeforces Round 77 (Rated for Div. 2)
感觉最近写代码的状态有点迷...还好这次最后两分钟过了D,不然就掉分了QAQ。
A. Heating
签到。
Code
/*
* Author: heyuhhh
* Created Time: 2019/11/27 21:53:49
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run(){
int c, sum; cin >> c >> sum;
int d = max(sum / c, 1), r = sum % c;
int ans = 0;
if(r == 0) {
ans = d * d * c;
} else {
for(int i = 1;; i++) {
ans += d * d;
--c; sum -= d;
if(sum == 0) break;
if(sum % c == 0) {
d = sum / c;
ans += c * d * d;
break;
}
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
B. Obtain Two Zeroes
分情况,列一下方程找关系即可。
Code
/*
* Author: heyuhhh
* Created Time: 2019/11/27 22:03:54
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run(){
int x, y; cin >> x >> y;
if(x > y) swap(x, y);
int f = 0;
if(2 * y - x >= 0 && (2 * y - x) % 3 == 0) {
int t = (2 * y - x) / 3;
if(x >= t && y >= 2 * t) f = 1;
}
if(2 * x - y >= 0 && (2 * x - y) % 3 == 0) {
int t = (2 * x - y) / 3;
if(x >= 2 * t && y >= t) f = 1;
}
if(f) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
C. Infinite Fence
题意:
现在有无穷多个砖块排成一行,现在从\(0\)开始,每\(r\)个涂一种颜色,每\(b\)个涂一种颜色。形式化地说,就是\(0,r,2r,\cdots\)以及\(0,b,2r,\cdots\)这些砖块各涂一种颜色。
如果存在一个位置\(x\),满足\(r|x,b|x\),那么\(x\)这个位置可以选择一种颜色去涂。
现在有多组询问,每组询问回答是否有颜色相同且连续的多个砖块,其个数小于\(k\)。
思路:
- 显然我们只需要考虑\(0\)~\(lcm(r,b)\)即可。
- 不妨设\(r<b\),那么\(q=b\% r\),也就相当于\(b\)每涂一次,只会在长度为\(r\)的区间中前进\(q\)(不考虑中间经过的完整的区间)。
- 显然,连续的砖块个数最多的情况,就是存在\(x,y\),使得\(|xr-yb|\)最小,也就是说某一次涂完\(b\)之后,这时的位置离\(r\)的倍数最近,那么下一次涂就可以尽可能远。
- 令\(p=r\% q\),之后即可确定出起点,然后找到终点,统计一下中间个数即可。
好像这个有个什么结论,不过这种思路也不是很复杂~
细节见代码:
Code
/*
* Author: heyuhhh
* Created Time: 2019/11/27 22:33:59
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
ll r, b, k;
void run(){
cin >> r >> b >> k;
if(r > b) swap(r, b);
if(b % r == 0) {
int d = b / r - 1;
if(d >= k) {
cout << "REBEL" << '\n';
} else cout << "OBEY" << '\n';
} else {
int q = b % r;
int p = r % q;
ll s;
if(p == 0) {
s = r - q;
} else s = r - p;
ll e = s + b;
int cnt = e / r - (s - 1) / r;
if(e % r == 0) --cnt;
if(cnt >= k) cout << "REBEL" << '\n';
else cout << "OBEY" << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
D. A Game with Traps
题意:
现在有一条长度为\(n\)的战线,你要带领一些士兵从\(0\)到\(n+1\)。
中间的某些位置可能存在陷阱,其位置为\(l_i\),深度为\(d_i\)。某些士兵有其敏捷度\(a_i\),若\(a_i<d_i\),他就会阵亡。
但是你,不会受到陷阱的影响,相反若对于某个\(l_i\),走到\(r_i\),能够拆除这个陷阱。
你当前可以进行如下操作:
- 花费一秒的时间,独立从\(x\)走到\(x-1\)或\(x+1\);
- 花费一秒的时间,带领士兵从\(x\)走到\(x+1\),此时你也要在\(x+1\)。
- 进行拆除陷阱的操作,不消耗时间。
问在\(t\)秒内,能够带领最多多少的士兵走到\(n+1\)的位置。
思路:
这个题题意稍微有点绕,但是思路不是很难。
很显然的我们可以二分答案。
然后直接模拟这个过程,贪心往前走就行。关键就是通过一个变量\(rbound\)来记录你走到右边的最远位置,因为拆除陷阱是,肯定是能拆的一次性拆完。我们利用\(rbound\)来统计贡献就行。
细节见代码:
Code
/*
* Author: heyuhhh
* Created Time: 2019/11/27 22:56:01
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5;
int m, n, k, t;
int a[N];
vector <pii> v[N];
bool chk(int x) {
ll c = 0;
int rb = 0;
int low = a[m - x + 1];
for(int i = 0; i <= n; i++) {
rb = max(rb, i);
if(sz(v[i + 1]) > 0) {
for(int j = 0; j < sz(v[i + 1]); j++) {
pii now = v[i + 1][j];
if(now.fi <= low || now.se <= rb) {}
else {
c += 2 * (ll)(now.se - rb);
rb = now.se;
}
}
}
if(++c > (ll)t) return false;
}
return true;
}
void run(){
for(int i = 1; i <= m; i++) cin >> a[i];
sort(a + 1, a + m + 1);
for(int i = 1; i <= k; i++) {
int l, r, d; cin >> l >> r >> d;
v[l].push_back(MP(d, r));
}
for(int i = 1; i <= n; i++) if(sz(v[i])) {
sort(v[i].begin(), v[i].end(), [&](pii A, pii B) {
if(A.fi != B.fi) return A.fi > B.fi;
else return A.se > B.se; });
}
int l = 1, r = m + 1, mid;
while(l < r) {
mid = (l + r) >> 1;
if(chk(mid)) l = mid + 1;
else r = mid;
}
cout << l - 1 << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
while(cin >> m >> n >> k >> t) run();
return 0;
}
E. Tournament
题意:
现在有\(n\)个选手参加比赛,你的朋友也在里面。
每个选手有一个力量值\(i\),显然在两两的比赛中力量值大的会胜出。
比赛的规则就是每一轮两两比赛,最后胜者进入下一轮,然后重复此过程直至某一人胜出。
你的朋友很可能GG,但是你可以贿赂那些人,贿赂的代价为\(a_i\)。
问最后使得你的朋友胜出的最小代价是多少。
思路:
感觉很有意思的一个题,也不是很好想(菜就对了)。
显然如果我们倒着来考虑整个比赛的过程,那么会形成一颗满二叉树。
第二层有两个结点,一个结点是你的朋友,另一个结点是你的对手。那么可以当作你的对手在之前KO了\(\frac{n}{2}\)个人,而此时你必须贿赂你的对手来获得胜利(如果他力量比你低,那代价为\(0\),因为此时的对手肯定是最后一个人)。
同理,之后到了第三层,你朋友的对手会打败\(\frac{n}{4}\)个人...然后依次类推。
之后有一个引理:
- 若当前是第\(x\)层,那么你会遇到\(x-1\)个对手,所有的对手会打败\(tot=\frac{n}{2}+\cdots+\frac{n}{2^{x-1}}\)个人。那么,下一轮你能够从后面\(tot+1\)个位置任选一个人(当然不能选过)当作你的对手。
证明的话就是对于每一个规模的问题,你肯定要贿赂当前的最强者。又因为可以任意安排策略,所以你一定能够在后面(力量值比较大的部分)选择你的对手。同时每一个对手又能不断增加击败人数...然后yy一下就有了。
如果能将树的思路和这个引理想到并且想清楚了。那么用一个小根堆模拟一下就行。
还是挺巧妙的hhh思路转换一下就出来了。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2019/11/28 22:15:03
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <queue>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;
int n;
int a[N];
void run(){
for(int i = 1; i <= n; i++) cin >> a[i];
reverse(a + 1, a + n + 1);
priority_queue <int, vector<int>, greater<int> > q;
int now = 1;
q.push(a[now++]);
ll ans = 0;
int win = n / 2;
while(!q.empty()) {
int cur = q.top(); q.pop();
if(cur == -1) break;
ans += cur;
for(int i = 1; i <= win; i++) q.push(a[now++]);
win /= 2;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
while(cin >> n) run();
return 0;
}
重要的是自信,一旦有了自信,人就会赢得一切。