感觉最近写代码的状态有点迷...还好这次最后两分钟过了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; }